<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>SQL / T-SQL</title>
        <link>http://blog.caffeinatedsoftware.com/category/15.aspx</link>
        <description>Random ramblings about my favorite DB</description>
        <language>en-US</language>
        <copyright>&lt;i&gt;&lt;b&gt;Caffeinated&lt;/b&gt;&lt;/i&gt; Software</copyright>
        <managingEditor>robbiep@caffeinatedsoftware.com</managingEditor>
        <generator>Subtext Version 1.9.5.176</generator>
        <item>
            <title>Storing images in the database – good or bad idea?</title>
            <link>http://blog.caffeinatedsoftware.com/archive/2007/06/26/storing-images-in-the-database--good-or-bad-idea.aspx</link>
            <description>&lt;p&gt;&lt;img align="left" alt="" src="http://blog.caffeinatedsoftware.com/images/blog_caffeinatedsoftware_com/062607_1617_Storingimag1.jpg" /&gt;As many of you know, I write real estate web applications for fun and profit. I have to admit it really is an interesting area for innovative web applications. After all, writing a modern IDX solution requires taking advantage of AJAX technologies, mastering a web based mapping platform (like Microsoft Virtual Earth or Google Maps), integration w/ 3&lt;sup&gt;rd&lt;/sup&gt; party APIs and web sites (such as Zillow or Trulia), pretty dynamic SQL, and handling large amounts of graphical images. Needless to say, it can pose some interesting technical challenges at times. &lt;/p&gt;
&lt;p&gt;I'm in the midst of an application architecture upgrade; I'm currently debating how I want store my MLS images. I currently store broker specific images in a database (currently just agent photos and property management photos). My biggest customer (&lt;a href="http://www.rentseattle.com"&gt;Real Property Associates&lt;/a&gt;) has about 70 agent photos and 2000 property images stored in a database, (I currently use ASP.NET HTTP handlers to extract images out of the DB and re-size said image on the fly before I send the response stream to the browser). The NWMLS images are on the file system scattered in one of a thousand subdirectories.  &lt;/p&gt;
&lt;p&gt;Although this arrangement is more efficient than storing all 474,589 or so NWMLS images in a single directory, it's painful to deal with. Deleting photos for sold or expired listings is like &lt;a href="http://en.wikipedia.org/wiki/Spelunking"&gt;going spelunking&lt;/a&gt; instead of doing a DELETE * FROM … WHERE … SQL query. SELECT queries are a lot more flexible that DIR commands. Modifying data only requires one set of DB permissions instead of setting file system permissions on a thousand directories. I don't have to worry about the physical location of my data, since it's just a SELECT query away (regarding of where SQL ends up putting it). Adding meta data is just an ALTER TABLE … ADD COLUMN … SQL command away. In short, even if SQL Server is slower than the file system, the &lt;a href="http://forums.asp.net/p/1096999/1658599.aspx"&gt;benefits of dealing with it&lt;/a&gt; instead are worth the price, &lt;em&gt;so far&lt;/em&gt;. &lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.sqlteam.com/article/images-and-sql-server"&gt;Conventional wisdom is that you don't store images in SQL server&lt;/a&gt;. Unfortunately, my good experience with smaller data sets is leading me to believe that conventional wisdom is wrong. Then again, there's a world of difference between 2000 images and a number hovering 25K shy of half a million images. In my case, the images tend to be smaller JPEGs (about 400 x 300 in size) usually hovering around 50K, and I suspect (though I don't know), as long as the size of the images are small-ish, the performance penalty you'll pay &lt;em&gt;appears&lt;/em&gt; to be comparatively is minor. My DBA guru friends have told me as long as the image sizes are small, it should be fine. SQL finding a BLOB via a primary key should be pretty quick. &lt;/p&gt;
&lt;p&gt;Of course, the only way to find out for sure is to go for it (and see if you regret it later). I suppose, I already know the answer I want to hear. I just want to feel good about it before I go ahead and database-tize my NWMLS image set. Rumor has it that &lt;a href="http://blogs.msdn.com/pedram/archive/2007/06/04/store-any-data-in-sql-server-2008-katmai.aspx"&gt;SQL 2008 has a new FileStream datatype&lt;/a&gt;, that stores BLOBs in the file system, but yet remain an integral part of the database with &lt;a href="http://msdn2.microsoft.com/en-us/library/aa363764.aspx"&gt;&lt;em&gt;transactional consistency&lt;/em&gt;&lt;/a&gt;, so perhaps I should wait? Ironically, doing nothing (and waiting for Microsoft to fix the problem) is sometimes the smartest design decision you can make. &lt;/p&gt;
&lt;p&gt;So does anybody have any good or bad experiences with storing images in their DB / Web applications? How big of a dataset are you storing in the DB? How big of a dataset are you displaying in the web browser window? How do the &lt;a href="http://www.flexmls.com/blog"&gt;MLS Vendors&lt;/a&gt; deal with this problem? &lt;/p&gt;&lt;img src="http://blog.caffeinatedsoftware.com/aggbug/29.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>&lt;i&gt;&lt;b&gt;Caffeinated&lt;/b&gt;&lt;/i&gt; Software</dc:creator>
            <guid>http://blog.caffeinatedsoftware.com/archive/2007/06/26/storing-images-in-the-database--good-or-bad-idea.aspx</guid>
            <pubDate>Tue, 26 Jun 2007 16:17:26 GMT</pubDate>
            <wfw:comment>http://blog.caffeinatedsoftware.com/comments/29.aspx</wfw:comment>
            <comments>http://blog.caffeinatedsoftware.com/archive/2007/06/26/storing-images-in-the-database--good-or-bad-idea.aspx#feedback</comments>
            <slash:comments>11</slash:comments>
            <wfw:commentRss>http://blog.caffeinatedsoftware.com/comments/commentRss/29.aspx</wfw:commentRss>
            <trackback:ping>http://blog.caffeinatedsoftware.com/services/trackbacks/29.aspx</trackback:ping>
        </item>
        <item>
            <title>Is there a better way to compute a Median in SQL?</title>
            <link>http://blog.caffeinatedsoftware.com/archive/2007/05/01/Is-there-a-better-way-to-compute-a-Median.aspx</link>
            <description>I'm currently playing with random ideas I have for Nimitz (aka the next version of my NWMLS search tool), and one of the things I'm thinking about is displaying the Median value of properties that match an arbitrary search criteria. I already do something similar to this now on &lt;a href="http://www.raincityguide.com/2006/04/25/rcgs-zearch-is-released/"&gt;Zearch &lt;/a&gt;(the current version of my NWMLS search tool). with MIN, MAX, and AVG. So I wrote a Stored Proc (using MS SQL 2005 features), and came up with the following. (FYI - I was inspired by &lt;a href="http://pluralsight.com/blogs/dan/archive/2005/09/29/15082.aspx"&gt;this blog post&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt;  &lt;span class="kwrd"&gt;PROC&lt;/span&gt; [dbo].[GetMedian]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;(&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;    @Col &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(100),&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    @&lt;span class="kwrd"&gt;Table&lt;/span&gt; &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(100),&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    @SqlWhere  &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(1000)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&lt;span class="kwrd"&gt;AS&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @&lt;span class="kwrd"&gt;Count&lt;/span&gt; &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;INT&lt;/span&gt;, @MiddleRow &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;INT&lt;/span&gt;, @Median &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;INT&lt;/span&gt; &lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @SqlAll nvarchar(&lt;span class="kwrd"&gt;MAX&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt; &lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @SqlAll = &lt;span class="str"&gt;'WITH MLSSTATS AS '&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @SqlAll = @SqlAll + &lt;span class="str"&gt;'('&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @SqlAll = @SqlAll + &lt;span class="str"&gt;'SELECT ROW_NUMBER() OVER (ORDER BY '&lt;/span&gt; + @Col&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @SqlAll = @SqlAll + &lt;span class="str"&gt;' DESC ) AS RowNum , '&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @SqlAll = @SqlAll + &lt;span class="str"&gt;'(SELECT COUNT(*) FROM '&lt;/span&gt; +@&lt;span class="kwrd"&gt;Table&lt;/span&gt; + &lt;span class="str"&gt;' '&lt;/span&gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @SqlAll = @SqlAll + @SqlWhere + &lt;span class="str"&gt;') As Cnt,'&lt;/span&gt; &lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @SqlAll = @SqlAll + @Col&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @SqlAll = @SqlAll + &lt;span class="str"&gt;' FROM '&lt;/span&gt; + @&lt;span class="kwrd"&gt;Table&lt;/span&gt; + &lt;span class="str"&gt;' '&lt;/span&gt; + @SqlWhere &lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @SqlAll = @SqlAll + &lt;span class="str"&gt;') '&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @SqlAll = @SqlAll + &lt;span class="str"&gt;'select AVG('&lt;/span&gt; + @Col +&lt;span class="str"&gt;') from MLSSTATS '&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @SqlAll = @SqlAll + &lt;span class="str"&gt;'where rownum  IN((Cnt + 1) / 2, (Cnt + 2) / 2)'&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt; &lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;    &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;    &lt;span class="kwrd"&gt;EXEC&lt;/span&gt; sp_executesql @SqlAll &lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;END&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;So if, let's say, I wanted to find the median value of all the houses currently listed in the city of Redmond, I'd do something like this...&lt;br /&gt;
&lt;/p&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;GetMedian &lt;span class="str"&gt;'ListPrice'&lt;/span&gt;, &lt;span class="str"&gt;'MLSTABLE'&lt;/span&gt;, &lt;span class="str"&gt;'WHERE City in ('&lt;/span&gt;&lt;span class="str"&gt;'Redmond'&lt;/span&gt;&lt;span class="str"&gt;')'&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And then the proc would do it's dynamic SQL black magic and end up executing this...&lt;/p&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;WITH&lt;/span&gt; MLSSTATS &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;(&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; ROW_NUMBER() &lt;span class="kwrd"&gt;OVER&lt;/span&gt; (&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; ListPrice &lt;span class="kwrd"&gt;DESC&lt;/span&gt; ) &lt;span class="kwrd"&gt;AS&lt;/span&gt; RowNum , &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;(&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; MLSTABLE &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; City &lt;span class="kwrd"&gt;in&lt;/span&gt; (&lt;span class="str"&gt;'Redmond'&lt;/span&gt;)) &lt;span class="kwrd"&gt;As&lt;/span&gt; Cnt,&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;ListPrice &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; MLSTABLE&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; City &lt;span class="kwrd"&gt;in&lt;/span&gt; (&lt;span class="str"&gt;'Redmond'&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;&lt;span class="kwrd"&gt;select&lt;/span&gt; &lt;span class="kwrd"&gt;AVG&lt;/span&gt;(ListPrice)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&lt;span class="kwrd"&gt;from&lt;/span&gt; MLSSTATS &lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&lt;span class="kwrd"&gt;where&lt;/span&gt; rownum  &lt;span class="kwrd"&gt;IN&lt;/span&gt;((Cnt + 1) / 2, (Cnt + 2) / 2)&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
The SQL is ugly, but that's that nature of the beast. Anyway, the problem is that I really want do to this...&lt;/p&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;AVG&lt;/span&gt;(listprice), MEDIAN(&lt;span class="str"&gt;'ListPrice'&lt;/span&gt;, &lt;span class="str"&gt;'MLSTABLE'&lt;/span&gt;, &lt;span class="str"&gt;'WHERE City = '&lt;/span&gt;&lt;span class="str"&gt;'Redmond'&lt;/span&gt;&lt;span class="str"&gt;''&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; MLSTABLE&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; City = &lt;span class="str"&gt;'Redmond'&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
Or better yet, try to implement Median as a user defined aggregate function in C# / CLR language so it's even easier to use like so...&lt;/p&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;AVG&lt;/span&gt;(listprice), MEDIAN(ListPrice)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; MLSTABLE&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; City = &lt;span class="str"&gt;'Redmond'&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
According the above blog post it can't be done in a CLR language (which I don't understand). I guess user defined aggregates written in a CLR language only get the values of a set one at a time, instead of the entire set (which you would obviously need to compute a median)? Either way, I'm wondering if there's a way to convert my ugly proc into an ugly function instead? I think what's tripping me up, is that I need to define a variable that's accessible from dynamic SQL and returnable from the function that calls it.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;&lt;img src="http://blog.caffeinatedsoftware.com/aggbug/20.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>&lt;i&gt;&lt;b&gt;Caffeinated&lt;/b&gt;&lt;/i&gt; Software</dc:creator>
            <guid>http://blog.caffeinatedsoftware.com/archive/2007/05/01/Is-there-a-better-way-to-compute-a-Median.aspx</guid>
            <pubDate>Tue, 01 May 2007 15:38:58 GMT</pubDate>
            <wfw:comment>http://blog.caffeinatedsoftware.com/comments/20.aspx</wfw:comment>
            <comments>http://blog.caffeinatedsoftware.com/archive/2007/05/01/Is-there-a-better-way-to-compute-a-Median.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://blog.caffeinatedsoftware.com/comments/commentRss/20.aspx</wfw:commentRss>
            <trackback:ping>http://blog.caffeinatedsoftware.com/services/trackbacks/20.aspx</trackback:ping>
        </item>
    </channel>
</rss>