创建包含目标列表之外的移动的查询

时间:2015-05-22 09:21:38

标签: sql sql-server

给出一个容器表及其当前位置:

Date         Container    Location    Scrapped
---------------------------------------------
2015/08/25   Container1   A
2015/08/25   Container2   B
2015/08/25   Container3   C
2015/08/26   Container1   D
2015/08/26   Container2   A
2015/08/26   Container3   B
2015/08/27   Container1   D              x
2015/08/27   Container4   B
2015/08/27   Container2   C
2015/08/27   Container3   A

我需要的是一个给定日期的动作列表。因此,我们将2015/08/26作为所需日期,输出应如下所示:

Date         Container    From   To   Scrapped
----------------------------------------------
2015/08/26   Container1   A      D
2015/08/26   Container2   B      A
2015/08/26   Container3   C      B
2015/08/27   Container1   D      D       x
2015/08/27   Container4   null   B
2015/08/27   Container2   A      C
2015/08/27   Container3   B      A

创建一个通过enpoints提供给我的查询非常简单:

select
    Date,
    Container,
    Location as [To],
    Scrapped
from
    ContainerMovements
where
    Date >= '2015/08/26'

但是如何通过访问旧日期中的相应行来填充“发件人”列?我很确定它必须是某种左(或者如果你把列顺序称为右)加入,因为新容器可以出现并且From列可以为null,但我现在只是被卡住了在那。

该表位于SQL Server 2008 R2中。

为了简化here everything is pre-defined at SQLfiddle

4 个答案:

答案 0 :(得分:1)

执行下面的self join操作:

SELECT [Current].[Date], 
Prev.Container, 
Prev.Location [FROM], 
[Current].Location [TO], 
[Current].Scrapped

FROM

(
 SELECT [Date], 
 Container, 
 Location, 
 Scrapped, 
 ROW_NUMBER() OVER (PARTITION BY Container ORDER BY [Date]) rown
FROM dbo.ContainerMovements
) Prev

JOIN

(
 SELECT [Date], 
 Container, 
 Location, 
 Scrapped, 
 ROW_NUMBER() OVER (PARTITION BY Container ORDER BY [Date]) rown
FROM dbo.ContainerMovements
) [Current]

on Prev.Container = [Current].Container 
AND Prev.rown + 1 = [Current].rown 
AND [Current].[Date] = '2015/08/26'

答案 1 :(得分:1)

这个给出了您的预期结果。 Demo fiddle is here

DECLARE @date DATE = '20150826'

SELECT t1.[Date], t1.Container, 
       (SELECT TOP(1) t2.Location 
               FROM Table1 t2
               WHERE t2.Container = t1.Container AND t2.[date] < t1.[date]
               ORDER BY t2.[Date] DESC ) [from], 
        t1.Location [To], t1.Scrapped
FROM Table1 t1
WHERE t1.[Date] >= @date
ORDER BY t1.[Date]

输出:

|                     Date |  Container |   from | To | Scrapped |
|--------------------------|------------|--------|----|----------|
| August, 26 2015 00:00:00 | Container1 |      A |  D |   (null) |
| August, 26 2015 00:00:00 | Container2 |      B |  A |   (null) |
| August, 26 2015 00:00:00 | Container3 |      C |  B |   (null) |
| August, 27 2015 00:00:00 | Container1 |      D |  D |        x |
| August, 27 2015 00:00:00 | Container4 | (null) |  B |   (null) |
| August, 27 2015 00:00:00 | Container2 |      A |  C |   (null) |
| August, 27 2015 00:00:00 | Container3 |      B |  A |   (null) |

答案 2 :(得分:1)

试试这个,这里是SQL fiddle

SELECT [Date]
    ,[Container]
    ,[From]
    ,[To]
    ,Scrapped
FROM (
    SELECT ct.DATE
        ,row_number() OVER (
            PARTITION BY ct.Container
            ,ct.DATE ORDER BY frm.DATE DESC
            ) AS row_num
        ,ct.Container
        ,frm.Location AS [FROM]
        ,ct.Location AS [To]
        ,Scrapped = CASE 
            WHEN ct.Scrapped = 0
                THEN ''
            ELSE 'x'
            END
    FROM ContainerMovements ct
    LEFT JOIN ContainerMovements frm ON ct.Container = frm.Container
        AND frm.[Date] < ct.[Date]
    WHERE ct.DATE >= '2015/08/26'
    ) tbl
WHERE tbl.row_num = 1
ORDER BY tbl.DATE

答案 3 :(得分:1)

FULL JOIN的另一个版本:

DECLARE @t TABLE(d DATE, c VARCHAR(20), l CHAR(1))
DECLARE @d DATE = '2015/08/26'

INSERT INTO @t VALUES
('2015/08/25',   'Container1',   'A'),
('2015/08/25',   'Container2',   'B'),
('2015/08/25',   'Container3',   'C'),
('2015/08/26',   'Container1',   'D'),
('2015/08/26',   'Container2',   'A'),
('2015/08/26',   'Container3',   'B'),
('2015/08/27',   'Container1',   'D'),
('2015/08/27',   'Container4',   'B'),
('2015/08/27',   'Container2',   'C'),
('2015/08/27',   'Container3',   'A')

SELECT tn.d, tn.c, tp.l f, tn.l t, CASE WHEN tp.l = tn.l THEN 'x' END s
FROM @t tn
FULL JOIN @t tp ON tn.c = tp.c AND tn.d = DATEADD(dd, 1, tp.d)
WHERE tn.d IN(@d, DATEADD(dd, 1, @d))

输出:

d           c           f    t  s
2015-08-26  Container1  A    D  NULL
2015-08-26  Container2  B    A  NULL
2015-08-26  Container3  C    B  NULL
2015-08-27  Container1  D    D  x
2015-08-27  Container4  NULL B  NULL
2015-08-27  Container2  A    C  NULL
2015-08-27  Container3  B    A  NULL