表变换

时间:2015-03-30 11:39:42

标签: sql-server

我有一个表转换问题。这是一个理由结果问题。

举个例子,一群幼儿园学生会读一些书。当一个学生读完他的第一本书时,应该给他一个苹果作为礼物。他永远不会得到一个以上的苹果。但是,实际上结果并不总是如设计的那样,并且可能发生错误。可能不会给予苹果,也不会在错误的时间给予苹果。

以下两个表是示例数据:

create table #Reason (Student VARCHAR(20), BookName VARCHAR(20), FinishTime DateTime)
INSERT INTO #Reason VALUES
     ('Student1', 'Book11', '2015-03-01 13:00:00')
    ,('Student1', 'Book12', '2015-03-02 10:00:00')
    ,('Student1', 'Book13', '2015-03-03 18:00:00')
    ,('Student2', 'Book21', '2015-03-01 16:00:00')
    ,('Student2', 'Book22', '2015-03-02 18:00:00')
    ,('Student2', 'Book23', '2015-03-03 18:00:00')
    ,('Student2', 'Book24', '2015-03-04 18:00:00')
    ,('Student3', 'Book31', '2015-03-01 6:00:00')
    ,('Student3', 'Book32', '2015-03-02 8:00:00')
    ,('Student3', 'Book33', '2015-03-03 9:00:00')
    ,('Student3', 'Book34', '2015-03-04 12:00:00')
-----------------------------------------------------
create table #Result (Student VARCHAR(20), GiftName VARCHAR(20), GiftTime DateTime)
INSERT INTO #Result VALUES 
     ('Student1', 'Apple', '2015-03-01 13:01:00')
    ,('Student2', 'Apple', '2015-03-01 18:01:00') 
    ,('Student2', 'Apple', '2015-03-03 15:01:00') 
    ,('Student2', 'Apple', '2015-03-04 15:08:00')
    ,('Student2', 'Apple', '2015-03-04 15:09:00')
    ,('Student3', 'Apple', '2015-02-28 10:01:00')
    ,('Student4', 'Apple', '2015-04-28 10:01:00')

所需的输出表应该是(添加正确的列以指示是否在正确的时间给出苹果):

('Yes','Student1', 'Book11', '2015-03-01 13:00:00',  'Apple', '2015-03-01 13:01:00')
('Yes' ,'Student1', 'Book12', '2015-03-02 10:00:00',   NULL  , NULL                 )
('Yes' ,'Student1', 'Book13', '2015-03-03 18:00:00',   NULL  , NULL                 )
('Yes','Student2', 'Book21', '2015-03-01 16:00:00',  'Apple', '2015-03-01 18:01:00')
('No ','Student2', 'Book22', '2015-03-02 18:00:00',  'Apple', '2015-03-03 15:01:00')
('No ','Student2', 'Book23', '2015-03-03 18:00:00',  'Apple', '2015-03-04 15:08:00')
('No ','Student2', 'Book23', '2015-03-03 18:00:00',  'Apple', '2015-03-04 15:09:00')
('Yes' ,'Student2', 'Book24', '2015-03-04 18:00:00',   NULL  , NULL                 )
('No ','Student3', 'Book31', '2015-03-01 06:00:00',   NULL  , NULL                 )
('No ','Student3', NULL    , NULL                 ,  'Apple', '2015-02-28 10:01:00')
('Yes' ,'Student3', 'Book32', '2015-03-02 8:00:00' ,   NULL  , NULL                 )
('Yes' ,'Student3', 'Book33', '2015-03-03 9:00:00' ,   NULL  , NULL                 )
('Yes' ,'Student3', 'Book34', '2015-03-04 12:00:00',   NULL  , NULL                 )    
('No ','Student4', NULL    , NULL                 ,  'Apple', '2015-04-28 10:01:00')

2 个答案:

答案 0 :(得分:0)

试试这个SQL Fiddle

对于SQL Server 2008

;WITH Reason as
(
Select Student,BookName,FinishTime,ROW_NUMBER()OVER(PARTITION BY student ORDER BY FinishTime) BookNo,
  (SELECT MIN(FinishTime) FROM #Reason R2 WHERE R2.Student = R1.Student AND R2.FinishTime > R1.FinishTime) Next_Finish
FROM #Reason R1
),
Reason_WithGift as
(
SELECT *
FROM Reason Rn
),
Results as
(
SELECT Student,GiftName,GiftTime,ROW_NUMBER()OVER(PARTITION BY student ORDER BY GiftTime) GiftNo
FROM #Result
)
SELECT CASE WHEN ((BookNo = 1 AND GiftNo = 1) OR(BookNo <> 1 AND GiftNo IS NULL)) THEN 'Yes' ELSE 'No' END,ISNULL(Rn.Student,Rt.Student) Student,Rn.BookName,Rn.FinishTime,Rt.GiftName,Rt.GiftTime
FROM Reason_WithGift Rn
FULL OUTER JOIN Results Rt
    ON Rt.Student = Rn.Student 
        AND Rt.GiftTime BETWEEN Rn.FinishTime 
        AND ISNULL(Next_Finish,'2999/12/31')
ORDER BY ISNULL(Rn.Student,Rt.Student),Rn.BookName

对于SQL Server 2012及更高版本

;WITH Reason as
(
Select Student,BookName,FinishTime,LEAD(FinishTime)OVER(partition by student order by FinishTime) Next_Finish,ROW_NUMBER()OVER(PARTITION BY student ORDER BY FinishTime) BookNo
FROM #Reason
),
Reason_WithGift as
(
SELECT *
FROM Reason Rn
),
Results as
(
SELECT Student,GiftName,GiftTime,ROW_NUMBER()OVER(PARTITION BY student ORDER BY GiftTime) GiftNo
FROM #Result
)
SELECT IIF((BookNo = 1 AND GiftNo = 1) OR(BookNo <> 1 AND GiftNo IS NULL),'Yes','No'),ISNULL(Rn.Student,Rt.Student) Student,Rn.BookName,Rn.FinishTime,Rt.GiftName,Rt.GiftTime
FROM Reason_WithGift Rn
FULL OUTER JOIN Results Rt
    ON Rt.Student = Rn.Student 
        AND Rt.GiftTime BETWEEN Rn.FinishTime 
        AND ISNULL(Next_Finish,'2999/12/31')
ORDER BY ISNULL(Rn.Student,Rt.Student),Rn.BookName

答案 1 :(得分:0)

在ughai的帮助下,我修改了查询,它确实有效。再次感谢ughaim!

但我不知道如何发布我的更改。

改变:

  1. 摆脱reason_withgift临时表

  2. 更改结果临时表,类似于原因表

  3. 使用以下内容替换where子句

    中的时间条件

    AND Reason.FinishTime&lt; = Result.GiftTime AND Reason.Next_FinishTime&gt; = Result.GiftTime