<?xml version="1.0" encoding="UTF-8"?><!-- generator="wordpress/2.2.2" -->
<rss version="2.0" 
	xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
	<title>Comments on: How to select the first/least/max row per group in SQL</title>
	<link>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/</link>
	<description>Stay curious!</description>
	<pubDate>Sat, 30 Aug 2008 04:29:19 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.2.2</generator>

	<item>
		<title>By: Joana</title>
		<link>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-15015</link>
		<author>Joana</author>
		<pubDate>Sat, 16 Aug 2008 02:54:10 +0000</pubDate>
		<guid>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-15015</guid>
		<description>I wrote a nice comment but didnt see the antispam task! lost everything.
I was so happy now im not!:-(
well, thanks for the post anyway, helped me a lot.;-)</description>
		<content:encoded><![CDATA[<p>I wrote a nice comment but didnt see the antispam task! lost everything.<br />
I was so happy now im not!:-(<br />
well, thanks for the post anyway, helped me a lot.;-)</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Xaprb</title>
		<link>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14965</link>
		<author>Xaprb</author>
		<pubDate>Fri, 08 Aug 2008 15:41:14 +0000</pubDate>
		<guid>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14965</guid>
		<description>Sunil, see http://www.xaprb.com/blog/2008/08/08/how-to-select-the-nth-greatestleastfirstlast-row-in-sql/</description>
		<content:encoded><![CDATA[<p>Sunil, see <a href="http://www.xaprb.com/blog/2008/08/08/how-to-select-the-nth-greatestleastfirstlast-row-in-sql/" rel="nofollow">http://www.xaprb.com/blog/2008/08/08/how-to-select-the-nth-greatestleastfirstlast-row-in-sql/</a></p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Sunil</title>
		<link>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14955</link>
		<author>Sunil</author>
		<pubDate>Thu, 07 Aug 2008 19:53:02 +0000</pubDate>
		<guid>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14955</guid>
		<description>The article and the responses have been very helpful. I am trying to solve a somewhat related problem. In terms of the example in this article, What is the best way to query
1) Sum of min price of all types?
2) Sum of 2nd highest price of all types?

Thanks.</description>
		<content:encoded><![CDATA[<p>The article and the responses have been very helpful. I am trying to solve a somewhat related problem. In terms of the example in this article, What is the best way to query<br />
1) Sum of min price of all types?<br />
2) Sum of 2nd highest price of all types?</p>
<p>Thanks.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: AL0NE</title>
		<link>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14903</link>
		<author>AL0NE</author>
		<pubDate>Sat, 26 Jul 2008 23:03:21 +0000</pubDate>
		<guid>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14903</guid>
		<description>This article is very useful.. I want to thank you for it..
I've question please ...
How can I select the top 1 news ordered by date and time in each category without using the subqueries ..I was trying to do it with "One-pass technique" you talked about in this article but it didn't work because the "GROUP BY" statement works before the "ORDER BY" (which I use it to order the news by date and time ) .. but I couldn't get it ..
Thank you ..</description>
		<content:encoded><![CDATA[<p>This article is very useful.. I want to thank you for it..<br />
I&#8217;ve question please &#8230;<br />
How can I select the top 1 news ordered by date and time in each category without using the subqueries ..I was trying to do it with &#8220;One-pass technique&#8221; you talked about in this article but it didn&#8217;t work because the &#8220;GROUP BY&#8221; statement works before the &#8220;ORDER BY&#8221; (which I use it to order the news by date and time ) .. but I couldn&#8217;t get it ..<br />
Thank you ..</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: M A Roberts</title>
		<link>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14896</link>
		<author>M A Roberts</author>
		<pubDate>Wed, 23 Jul 2008 19:03:19 +0000</pubDate>
		<guid>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14896</guid>
		<description>This is an extraordinarily useful article, and I'll share how I used it to pull a mailing list in hopes that perhaps someone else with a similar type of issue might find practical value for the excellent techniques described in the article:

We rented data from a data broker. In this data, you have a few hundred thousand names, and these names are generally grouped together at buildings (a B-to-B type environment) and have job titles. There are thousands of buildings, meaning that it's not quite as simple as the fruit example, where there are only about five of them. This list doesn't get run all the time, so performance is not as much an issue for me as it may be for others - therefore, I used the "elegant" solution listed above (just above USE UNION), as it was the clearest and easiest to modify (even if it does have to make multiple passes with a correlated subquery).

What I did was:
-First, rank the job titles numerically to create a hierarchy (I did this on a separate table which gets added to the FROM list in the SELECT statement described in the next step with an INNER JOIN). It's more important for administrators to get the marketing piece than their peons, so they get a higher ranking. However: one may have the situation where many of the peons have the same job title (and the same rank), meaning that it's more difficult to pull the top 5 ranks as 1, 2, 3, 4, 5 because you may have one 1 and six or more 4s, for instance.

-SELECT the entire list into a separate table (can be temporary) that has an int IDENTITY column, sorting this list first by building ID and then by the job title rank. The third sort criteria (unspecified) seems based on the ID of the record which is fairly random (so if there are two fours, the one with the lower random ID number gets selected first) - but this could be specified with even more precision if desired.

-Then use the "elegant" query to select the top x# of records at each building based on the IDENTITY column, where the lowest identity number is always the highest-ranked job-title-holders, and on down the list until you hit the x# limit.

This ensures that no more than x# of people per building will get the mailing piece, and that at the very least the top dog(s) will get it and a few others. Other criteria can obviously be added to the sorting if desired based on whatever criteria one would like - whether they'd responded to prior offers, for instance - when it goes into the sub-table to get an IDENTITY value.

If I want to make sure that a certain group of buildings (say, ones with more than 20 names at the location) get y# (let's say five) of the pieces but ones with less than 10 get a lower number (x#, say three), then it is easy to SELECT these into two separate IDENTITY-set tables and then select from both of those tables with a UNION clause to get a final list.

Hope this practical example helps someone just like this article helped me.</description>
		<content:encoded><![CDATA[<p>This is an extraordinarily useful article, and I&#8217;ll share how I used it to pull a mailing list in hopes that perhaps someone else with a similar type of issue might find practical value for the excellent techniques described in the article:</p>
<p>We rented data from a data broker. In this data, you have a few hundred thousand names, and these names are generally grouped together at buildings (a B-to-B type environment) and have job titles. There are thousands of buildings, meaning that it&#8217;s not quite as simple as the fruit example, where there are only about five of them. This list doesn&#8217;t get run all the time, so performance is not as much an issue for me as it may be for others - therefore, I used the &#8220;elegant&#8221; solution listed above (just above USE UNION), as it was the clearest and easiest to modify (even if it does have to make multiple passes with a correlated subquery).</p>
<p>What I did was:<br />
-First, rank the job titles numerically to create a hierarchy (I did this on a separate table which gets added to the FROM list in the SELECT statement described in the next step with an INNER JOIN). It&#8217;s more important for administrators to get the marketing piece than their peons, so they get a higher ranking. However: one may have the situation where many of the peons have the same job title (and the same rank), meaning that it&#8217;s more difficult to pull the top 5 ranks as 1, 2, 3, 4, 5 because you may have one 1 and six or more 4s, for instance.</p>
<p>-SELECT the entire list into a separate table (can be temporary) that has an int IDENTITY column, sorting this list first by building ID and then by the job title rank. The third sort criteria (unspecified) seems based on the ID of the record which is fairly random (so if there are two fours, the one with the lower random ID number gets selected first) - but this could be specified with even more precision if desired.</p>
<p>-Then use the &#8220;elegant&#8221; query to select the top x# of records at each building based on the IDENTITY column, where the lowest identity number is always the highest-ranked job-title-holders, and on down the list until you hit the x# limit.</p>
<p>This ensures that no more than x# of people per building will get the mailing piece, and that at the very least the top dog(s) will get it and a few others. Other criteria can obviously be added to the sorting if desired based on whatever criteria one would like - whether they&#8217;d responded to prior offers, for instance - when it goes into the sub-table to get an IDENTITY value.</p>
<p>If I want to make sure that a certain group of buildings (say, ones with more than 20 names at the location) get y# (let&#8217;s say five) of the pieces but ones with less than 10 get a lower number (x#, say three), then it is easy to SELECT these into two separate IDENTITY-set tables and then select from both of those tables with a UNION clause to get a final list.</p>
<p>Hope this practical example helps someone just like this article helped me.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Isidoros</title>
		<link>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14770</link>
		<author>Isidoros</author>
		<pubDate>Fri, 20 Jun 2008 08:59:31 +0000</pubDate>
		<guid>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14770</guid>
		<description>try this out!

create a temporary table (by using the #)

create a cursor to select only the id of each group.

loop until end of cursor and select top 1 record for each group 
and insert the result to the temporary.

select all records of temporary and return the data

that worked for me! following is the store procedure i used...

CREATE PROCEDURE dbo.sp_GetExamsLastStatus (@FromDate datetime,
                                           @ToDate datetime)
	/*
	(
	@parameter1 int = 5,
	@parameter2 datatype OUTPUT
	)
	*/
AS
	-- Declare the variables to store the values returned by FETCH.
	DECLARE @ExamID int, @StatusDateTime datetime, @Status smallint;
	DECLARE @PrvExamID int;
	
	-- Create temporary table
	CREATE TABLE #ExamStatus(ExamID int, StatusDateTime datetime,Status smallint );
	
	-- create cursor
	DECLARE Exam_Cursor CURSOR FOR
		SELECT examstatus.ExamID, StatusDateTime, Status
		FROM  ExamStatus inner join Exam on examstatus.examid=exam.examid
		where exam.examdate between @FromDate and @ToDate
		ORDER BY ExamID, StatusDateTime DESC;
				
	-- open curson				
	OPEN Exam_Cursor;
	
	FETCH NEXT FROM Exam_Cursor 
	INTO @ExamID, @StatusDateTime, @Status;
	SET @PrvExamID=0;
	WHILE @@FETCH_STATUS = 0 --loop until end of file
	   BEGIN
		  if @ExamID@PrvExamID --if record changed
		  begin
			SET @PrvExamID=@ExamID --store new ID
					  
			--select the top 1 ordered by date record and
			--save it to the temporary file
		  insert into #ExamStatus (ExamID, StatusDateTime, Status)
		    SELECT  TOP (1) ExamID, StatusDateTime, Status
			FROM  ExamStatus
			WHERE        (ExamID = @ExamID)
			ORDER BY StatusDateTime DESC;
		  
		  END 
		  
		  FETCH NEXT FROM Exam_Cursor 
		        INTO @ExamID, @StatusDateTime, @Status;
	   END;
	CLOSE Exam_Cursor;
		
	DEALLOCATE Exam_Cursor;

	--show results
	--select ExamID, StatusDateTime, Status from #ExamStatus ;
	SELECT        #ExamStatus.ExamID, Exam.ExamDate, Exam.StartTime, Exam.ExamHours, #ExamStatus.StatusDateTime, #ExamStatus.Status, 
                  ExamClass.Description AS ClassDescription
    FROM          #ExamStatus INNER JOIN
                  Exam ON #ExamStatus.ExamID = Exam.ExamID LEFT OUTER JOIN
                  ExamClass ON Exam.SiteCenterID = ExamClass.SiteCenterID AND Exam.ClassID = ExamClass.ClassID
    ORDER BY Exam.ExamDate,Exam.StartTime;
	
	RETURN</description>
		<content:encoded><![CDATA[<p>try this out!</p>
<p>create a temporary table (by using the #)</p>
<p>create a cursor to select only the id of each group.</p>
<p>loop until end of cursor and select top 1 record for each group<br />
and insert the result to the temporary.</p>
<p>select all records of temporary and return the data</p>
<p>that worked for me! following is the store procedure i used&#8230;</p>
<p>CREATE PROCEDURE dbo.sp_GetExamsLastStatus (@FromDate datetime,<br />
                                           @ToDate datetime)<br />
	/*<br />
	(<br />
	@parameter1 int = 5,<br />
	@parameter2 datatype OUTPUT<br />
	)<br />
	*/<br />
AS<br />
	&#8211; Declare the variables to store the values returned by FETCH.<br />
	DECLARE @ExamID int, @StatusDateTime datetime, @Status smallint;<br />
	DECLARE @PrvExamID int;</p>
<p>	&#8211; Create temporary table<br />
	CREATE TABLE #ExamStatus(ExamID int, StatusDateTime datetime,Status smallint );</p>
<p>	&#8211; create cursor<br />
	DECLARE Exam_Cursor CURSOR FOR<br />
		SELECT examstatus.ExamID, StatusDateTime, Status<br />
		FROM  ExamStatus inner join Exam on examstatus.examid=exam.examid<br />
		where exam.examdate between @FromDate and @ToDate<br />
		ORDER BY ExamID, StatusDateTime DESC;</p>
<p>	&#8211; open curson<br />
	OPEN Exam_Cursor;</p>
<p>	FETCH NEXT FROM Exam_Cursor<br />
	INTO @ExamID, @StatusDateTime, @Status;<br />
	SET @PrvExamID=0;<br />
	WHILE @@FETCH_STATUS = 0 &#8211;loop until end of file<br />
	   BEGIN<br />
		  if @ExamID@PrvExamID &#8211;if record changed<br />
		  begin<br />
			SET @PrvExamID=@ExamID &#8211;store new ID</p>
<p>			&#8211;select the top 1 ordered by date record and<br />
			&#8211;save it to the temporary file<br />
		  insert into #ExamStatus (ExamID, StatusDateTime, Status)<br />
		    SELECT  TOP (1) ExamID, StatusDateTime, Status<br />
			FROM  ExamStatus<br />
			WHERE        (ExamID = @ExamID)<br />
			ORDER BY StatusDateTime DESC;</p>
<p>		  END </p>
<p>		  FETCH NEXT FROM Exam_Cursor<br />
		        INTO @ExamID, @StatusDateTime, @Status;<br />
	   END;<br />
	CLOSE Exam_Cursor;</p>
<p>	DEALLOCATE Exam_Cursor;</p>
<p>	&#8211;show results<br />
	&#8211;select ExamID, StatusDateTime, Status from #ExamStatus ;<br />
	SELECT        #ExamStatus.ExamID, Exam.ExamDate, Exam.StartTime, Exam.ExamHours, #ExamStatus.StatusDateTime, #ExamStatus.Status,<br />
                  ExamClass.Description AS ClassDescription<br />
    FROM          #ExamStatus INNER JOIN<br />
                  Exam ON #ExamStatus.ExamID = Exam.ExamID LEFT OUTER JOIN<br />
                  ExamClass ON Exam.SiteCenterID = ExamClass.SiteCenterID AND Exam.ClassID = ExamClass.ClassID<br />
    ORDER BY Exam.ExamDate,Exam.StartTime;</p>
<p>	RETURN</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Abdul</title>
		<link>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14769</link>
		<author>Abdul</author>
		<pubDate>Fri, 20 Jun 2008 06:23:33 +0000</pubDate>
		<guid>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14769</guid>
		<description>Thanks. You are great.
I always come back to this page :)</description>
		<content:encoded><![CDATA[<p>Thanks. You are great.<br />
I always come back to this page :)</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: sswong</title>
		<link>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14705</link>
		<author>sswong</author>
		<pubDate>Sun, 08 Jun 2008 16:57:34 +0000</pubDate>
		<guid>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14705</guid>
		<description>hi, refer to the second-cheapest of that type, the corelated way, i don't quite understand the count(*) for,
and another question is, what if i'm seeking for random 2 rows instead of the cheapest 2, i tried removing the price comparison, it doesn't work. anyone care to enlighten me? thanks</description>
		<content:encoded><![CDATA[<p>hi, refer to the second-cheapest of that type, the corelated way, i don&#8217;t quite understand the count(*) for,<br />
and another question is, what if i&#8217;m seeking for random 2 rows instead of the cheapest 2, i tried removing the price comparison, it doesn&#8217;t work. anyone care to enlighten me? thanks</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Michal Talaga</title>
		<link>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14690</link>
		<author>Michal Talaga</author>
		<pubDate>Tue, 03 Jun 2008 10:12:58 +0000</pubDate>
		<guid>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14690</guid>
		<description>Isn't the second method:

select type, variety, price
from fruits
where price = (select min(price) from fruits as f where f.type = fruits.type

just wrong?

It more or less assumes that price will be unique. If the same price was repeated for 2 types of fruits and it happend to be the minumum price for one of them, the other fruit would also be returned. 
Am I right?</description>
		<content:encoded><![CDATA[<p>Isn&#8217;t the second method:</p>
<p>select type, variety, price<br />
from fruits<br />
where price = (select min(price) from fruits as f where f.type = fruits.type</p>
<p>just wrong?</p>
<p>It more or less assumes that price will be unique. If the same price was repeated for 2 types of fruits and it happend to be the minumum price for one of them, the other fruit would also be returned.<br />
Am I right?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: jalil</title>
		<link>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14479</link>
		<author>jalil</author>
		<pubDate>Thu, 24 Apr 2008 17:53:35 +0000</pubDate>
		<guid>http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/#comment-14479</guid>
		<description>very helpful
thanks</description>
		<content:encoded><![CDATA[<p>very helpful<br />
thanks</p>
]]></content:encoded>
	</item>
</channel>
</rss>
