create table #Numbers(DateEntered datetime, Number int)
go

insert #Numbers values('07/01/00 12:00:00 PM', 1)
insert #Numbers values('07/01/00 12:01:00 PM', 2)
insert #Numbers values('07/01/00 12:02:00 PM', 3)
insert #Numbers values('07/02/00 12:00:00 PM', 998)
insert #Numbers values('07/02/00 12:01:00 PM', 999)
insert #Numbers values('07/02/00 12:02:00 PM', 1)
insert #Numbers values('07/03/00 12:00:00 PM', 998)
insert #Numbers values('07/03/00 12:01:00 PM', 1)
insert #Numbers values('07/03/00 12:02:00 PM', 999)
insert #Numbers values('07/03/00 12:03:00 PM', 2)
insert #Numbers values('07/03/00 12:04:00 PM', 3)
go

/*
The nature of this data is as follows:

>> A Number will never be duplicated on the same *day*.
>> The Number values are sequenced 1-999, wrapping back to 1 after 999
>> (1, 2, 3, 4, ..., 997, 998, 999, 1, 2, 3, ...)
>> There may be gaps in the data.
>> The data in the Numbers table can be *entered* out of order as in the
>> 07/03/00 examples
>> If 999 occurs in the same *day* as 1, everything prior to 999 must be
>> ordered *before* 1 and greater.  
>> The numbers will always be within a 500-number delta 
*/

-- To understand the query, you can analyze the output of
-- each derived table separately.
SELECT nn.DateEntered , nn.Number
FROM (
SELECT n.DateEntered , n.Number , 
       -- If 1 & 999 occur on same day And
       -- If ( Number < 999 & DateEntered is prior to Number = 1 ) Or
       -- ( Number = 999 ) then use DateEntered of Number = 1 itself
       CASE WHEN ( n.SameDay = 1 ) And
                 ( ( n.Number < 999 And n.DateEntered < n.OneDateEntered ) Or
                   ( n.Number = 999 ) )
                THEN n.OneDateEntered
        END AS NewDateEntered ,
        -- If 1 & 999 occur on same day, offset 1 to 1000 for sorting
        CASE WHEN SameDay = 1 And n.Number = 1
                THEN 1000
        END AS NewNumber
FROM  (
SELECT n1.DateEntered , n1.Number ,
       -- Mark rows where 1 & 999 occur on the same day
       ( CASE WHEN ( SELECT COUNT( * ) FROM #Numbers n2
                      WHERE n2.Number in ( 999 , 1 ) And
                            CONVERT( varchar , n1.DateEntered , 101 ) = 
                                CONVERT( varchar , n2.DateEntered , 101 ) ) = 2
                THEN 1
         END ) AS SameDay ,
        -- Get DateEntered for Number = 1, used later.
        ( SELECT n4.DateEntered FROM #Numbers n4
          WHERE CONVERT( varchar , n1.DateEntered , 101 ) = 
                CONVERT( varchar , n4.DateEntered , 101 ) And
                n4.Number = 1
        ) AS OneDateEntered
FROM #Numbers as n1
) AS n
) AS nn
-- Use the NewDateEntered and NewNumber values if present for sorting
ORDER BY COALESCE( nn.NewDateEntered , nn.DateEntered ) ,
         COALESCE( nn.NewNumber , nn.Number )

-- The query below was suggested by SQL Server MVP "BP Margolin"
SELECT DateEntered, Number
FROM (SELECT n1.*, minNumber, maxNumber
      FROM #Numbers as n1
            -- Find min & maximum number for each day
      JOIN (SELECT DateEntered = convert(char(10), DateEntered, 102),
                       minNumber = MIN( Number ),
                       maxNumber = MAX( Number )
            FROM #Numbers
            GROUP BY convert(char(10), DateEntered, 102)
      ) AS n2
      ON convert(char(10), n1.DateEntered, 102) =
           convert(char(10), n2.DateEntered, 102)
) AS n3
ORDER BY convert(char(10), DateEntered, 102),
         -- Since the values will be within 500-number DELTA , use that to
         -- offset values from 1 to 499
         CASE WHEN maxNumber <= minNumber + 500 THEN Number ELSE NULL END ,
         -- offset values from >= 500
         CASE WHEN maxNumber > minNumber + 500 
                 THEN ( CASE WHEN Number >= maxNumber - 500
                              THEN Number
                              ELSE Number + 1000
                        END )
                 ELSE NULL
         END
This page was last updated on May 01, 2006 04:28 PM.