简体   繁体   中英

Need a SQL Server query that gets sets of 3 rows based on a date given

I need to get 3 rows per set based on a date given (must be this date) but I want the rows to be based on this date as:

1 ( row where the date from the date column is the next date after given date )   
0 ( row where the date is the closest date prior to the date given )  
-1 ( prior to the date at 0 )

And add a column with the relative number.

** The dates for the same name and item will never repeat.

For example, a set of rows:

Row ID, Name, Item, Number, Date   
1       Andy, Item1, 12030, 2014-06-30  
2       Andy, Item1, 62030, 2014-03-31  
3       Andy, Item1, 30300, 2013-12-31  
4       Andy, Item1, 40030, 2013-10-31  
5       Andy, Item1, 50030, 2013-08-30
6       John, Item2, 50240, 2014-04-30
7       John, Item2, 41400, 2014-03-31
8       John, Item2, 40509, 2014-01-31
9       Andy, Item2, 24004, 2014-03-31
10      Andy, Item2, 20144, 2013-12-31   
11      Andy, Item2, 20450, 2013-09-30   
12      Andy, Item2, 25515, 2013-06-30

If I have 2014-03-15 as the date and search for 'Andy', I expect:

 Row ID, Item,   Date,        Relative Date
 2,      Item1,  2014-03-31,  1  
 3,      Item1,  2013-12-31,  0  
 4,      Item1,  2013-10-31,  -1
 9,      Item2,  2014-03-31,  1
10,      Item2,  2013-12-31,  0   
11,      Item2,  2013-09-30,  -1         

This is what I'm using which I have no issues switching if necessary:

DATEDIFF( quarter, 2014-03-31, date ) 

date BETWEEN DATEADD( quarter, -1, '20140315' ) AND   
DATEADD( day, 1 ( DATEADD ( quarter, 2, '20140315' ) )  

which returns:

 Row ID, Item,   Date,        Relative Date
 2,      Item1,  2014-06-30,  1  
 3,      Item1,  2014-03-31,  0  
 4,      Item1,  2013-12-31,  -1
 9,      Item2,  2014-03-31,  0
10,      Item2,  2013-12-31,  -1   

Is there a better way of doing this without date math? I don't think I can accomplish exactly what I want with date math because it's hard to capture the exact 3 rows I need.

Perhaps something with row_number()?

Something like...

CREATE TABLE #TEMP
(
    RowID int
    , Name varchar(25)
    , Item varchar(25)
    , Number int
    , [Date] datetime
)

INSERT INTO #TEMP
VALUES (1, 'Andy', 'Item1', 12030, '2014-06-30T00:00:00')  
, (2, 'Andy', 'Item1', 62030, '2014-03-31T00:00:00')  
, (3, 'Andy', 'Item1', 30300, '2013-12-31T00:00:00')  
, (4, 'Andy', 'Item1', 40030, '2013-10-31T00:00:00')  
, (5, 'Andy', 'Item1', 50030, '2013-08-30T00:00:00')  

DECLARE @Date datetime 
SET @Date = '2014-03-15T00:00:00'

CREATE TABLE #NameItem
(
    ID int identity(1,1)
    , Name varchar(25)
    , Item varchar(25)
)

CREATE TABLE #Results
(
    NIID int
    , RowID int
    , [Date] datetime
    , RelativeDate int
)

INSERT INTO #NameItem
(Name, Item)
SELECT DISTINCT Name, Item
FROM #TEMP a

INSERT INTO #Results
(NIID, RowID, [Date], RelativeDate)
SELECT a.ID, b.RowID, b.[Date], b.RelativeDate
FROM #NameItem a
CROSS APPLY (
                SELECT TOP 1 z.RowID, z.[Date], 1 AS RelativeDate
                FROM #TEMP z
                WHERE z.Name = a.Name
                AND z.Item = a.Item
                AND [Date] > @Date
                ORDER BY [Date]
            ) b

INSERT INTO #Results
(NIID, RowID, [Date], RelativeDate)
SELECT a.ID, b.RowID, b.[Date], b.RelativeDate
FROM #NameItem a
CROSS APPLY (
                SELECT TOP 1 z.RowID, z.[Date], 0 AS RelativeDate
                FROM #TEMP z
                WHERE z.Name = a.Name
                AND z.Item = a.Item
                AND [Date] < @Date
                ORDER BY [Date] DESC
            ) b

; with cte_0 as
(
    SELECT a.NIID, a.[Date]
    FROM #Results a
    WHERE a.RelativeDate = 0
)

INSERT INTO #Results
(NIID, RowID, [Date], RelativeDate)
SELECT b.ID, c.RowID, c.[Date], c.RelativeDate
FROM cte_0 a
INNER JOIN #NameItem b
    ON a.NIID = b.ID
CROSS APPLY (
                SELECT TOP 1 z.RowID, z.[Date], -1 AS RelativeDate
                FROM #TEMP z
                WHERE z.Name = b.Name
                AND z.Item = b.Item
                AND z.[Date] < a.[Date]
                ORDER BY [Date] DESC
            ) c


SELECT a.Name, a.Item, b.RowID, b.[Date], b.RelativeDate
FROM #NameItem a
INNER JOIN #Results b
    ON a.ID = b.NIID
ORDER BY a.ID, b.RelativeDate DESC 

DROP TABLE #NameItem
DROP TABLE #Results
DROP TABLE #TEMP

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM