一些难题

时间:2018-07-04 12:01:00

标签: sql sql-server

这是我的桌子:

date             time   
6/24/2018   13:42:21    
6/24/2018   22:43:42    
6/26/2018   9:32:41       
6/26/2018   14:45:32    
6/27/2018   15:04:21    
6/27/2018   19:05:44    
6/28/2018   2:03:44     
6/28/2018   4:05:44        
6/28/2018   15:05:44    
6/28/2018   20:03:32
6/29/2018   9:04:06       
6/29/2018   21:06:32    
6/30/2018   4:50:33      
6/30/2018   14:44:33    
6/30/2018   21:33:44    

它描述了人们进入建筑物的时间和日期,我需要这样的表格:

arrival date    arrival time    leaving date    leaving time
6/24/2018       13:42:21        6/24/2018       22:43:42
6/26/2018       9:32:41         6/26/2018       14:45:32
6/27/2018       15:04:21        6/28/2018       4:05:44
6/28/2018       15:05:44        6/28/2018       20:03:32
6/29/2018       9:04:06         6/30/2018       4:50:33
6/30/2018       14:44:33        6/30/2018       21:33:44

真正的问题是,如果有人在早上00到04之间退出buildig,则需要在表中作为离开时间

我尝试过:

SELECT t1.tfullname,
       t1.arrival_date,
       ks.arrival_time_new,
       t1.leaving_date,
       t1.leaving_time
FROM (SELECT MIN(arrival_day) AS arrival_time_new,
             arrival_date,
             tFullName
      FROM dbo.DB
      WHERE DATEPART(hh, arrival_day) NOT BETWEEN 00 AND 05
      GROUP BY arrival_date,
               tFullName) ks
     JOIN (SELECT tFullName,
                  arrival_date,
                  MIN(arrival_day) AS arrival_time,
                  MAX(leaving_day) AS leaving_time,
                  CASE
                       WHEN LEAD(DATEPART(hh, MIN(arrival_day)), 1, 0) OVER (ORDER BY tfullname) BETWEEN 00 AND 04 THEN LEAD(leaving_date, 1, leaving_date) OVER (ORDER BY tfullname)
                       ELSE leaving_date
                  END AS leaving_date,
                  CASE
                       WHEN LEAD(DATEPART(hh, MIN(arival_day)), 1, 0) OVER (ORDER BY arrival_date) BETWEEN 00 AND 04 THEN LEAD((SELECT MAX(leaving_day) AS leaving_time
                                                                                                                                FROM dbo.db
                                                                                                                                WHERE DATEPART(hh, arival_day) BETWEEN 00 AND 05
                                                                                                                                GROUP BY leaving_date,
                                                                                                                                         arrival_date),
                                                                                                                               1,
                                                                                                                               MAX(leaving_day)) OVER (ORDER BY arrival_date)
                       ELSE MAX(leaving_day)
                  END AS leaving_time
           FROM dbo.DB
           GROUP BY arrival_date,
                    leaving_date,
                    tFullName) t1 ON t1.arrival_date = ks.arrival_date
ORDER BY DATEPART(yy, t1.arrival_date),
         t1.arrival_date;

它导致了这个问题:

SQL Server子查询返回了多个值。当子查询遵循=,!=,<,<=,>,> =时,不允许这样做   例如,另外2个tble:

输入

names   date    time
Shh 6/6/2018    10:24
Iii     6/6/2018    10:34
Rrr 6/6/2018    10:55
Shh 6/6/2018    21:34
Iii     6/6/2018    22:34
Rrr 6/6/2018    22:55
Rrr 6/7/2018    3:34

输出

names   arrival date    arrival time    leaving_date    leaving time
Shh 6/6/2018    10:24   6/6/2018    21:34
Iii 6/6/2018    10:34   6/6/2018    22:34
Rrr 6/6/2018    10:55   6/7/2018    3:34

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

非常复杂。这是一个快速的答案...将尝试处理优化的查询。

但是结果符合您的预期

;WITH cte AS(

            SELECT date,
                    time,
                    DATEADD(MINUTE,-299,CONVERT(DATETIME,CONVERT(VARCHAR(100),date,112)+' '+CONVERT(VARCHAR(100),time,108))) AS Col3,
                    ROW_NUMBER() OVER(PARTITION BY 
                        CONVERT(DATE,DATEADD(MINUTE,-299,CONVERT(VARCHAR(100),date,112)+' '+CONVERT(VARCHAR(100),time,108)))
                        ORDER BY DATEADD(MINUTE,-299,CONVERT(DATETIME,CONVERT(VARCHAR(100),date,112)+' '+CONVERT(VARCHAR(100),time,108)))
                        ) AS RN,
                    ROW_NUMBER() OVER(PARTITION BY 
                        CONVERT(DATE,DATEADD(MINUTE,-299,CONVERT(VARCHAR(100),date,112)+' '+CONVERT(VARCHAR(100),time,108)))
                        ORDER BY DATEADD(MINUTE,-299,CONVERT(DATETIME,CONVERT(VARCHAR(100),date,112)+' '+CONVERT(VARCHAR(100),time,108))) DESC
                        ) AS RN1,
                    CONVERT(DATE,DATEADD(MINUTE,-299,CONVERT(VARCHAR(100),date,112)+' '+CONVERT(VARCHAR(100),time,108))) AS Date1
            FROM Table1
            )

SELECT DISTINCT
    T1.date AS [arrival date],T1.time AS [arrival time],
    T2.date AS [leaving date],T2.time AS [leaving time]
FROM cte AS T1
INNER JOIN cte AS T2
    ON T1.Date1=T2.Date1
WHERE T1.RN=1
    AND T2.RN1=1

SQL Fiddle

-问题更改后编辑:

;WITH cte AS(

            SELECT names,
                    date,
                    time,
                    DATEADD(MINUTE,-299,CONVERT(DATETIME,CONVERT(VARCHAR(100),date,112)+' '+CONVERT(VARCHAR(100),time,108))) AS Col3,
                    ROW_NUMBER() OVER(PARTITION BY 
                        names,CONVERT(DATE,DATEADD(MINUTE,-299,CONVERT(VARCHAR(100),date,112)+' '+CONVERT(VARCHAR(100),time,108)))
                        ORDER BY DATEADD(MINUTE,-299,CONVERT(DATETIME,CONVERT(VARCHAR(100),date,112)+' '+CONVERT(VARCHAR(100),time,108)))
                        ) AS RN,
                    ROW_NUMBER() OVER(PARTITION BY 
                        names,CONVERT(DATE,DATEADD(MINUTE,-299,CONVERT(VARCHAR(100),date,112)+' '+CONVERT(VARCHAR(100),time,108)))
                        ORDER BY DATEADD(MINUTE,-299,CONVERT(DATETIME,CONVERT(VARCHAR(100),date,112)+' '+CONVERT(VARCHAR(100),time,108))) DESC
                        ) AS RN1,
                    CONVERT(DATE,DATEADD(MINUTE,-299,CONVERT(VARCHAR(100),date,112)+' '+CONVERT(VARCHAR(100),time,108))) AS Date1
            FROM Table2
            )

SELECT DISTINCT
    T1.names,
    T1.date,T1.time,
    T2.date,T2.time
FROM cte AS T1
INNER JOIN cte AS T2
    ON T1.Date1=T2.Date1
    AND T1.names=T2.names
WHERE T1.RN=1
    AND T2.RN1=1
ORDER BY T1.date

SQL Fiddle 2

答案 1 :(得分:1)

似乎行的语义(是在行中还是在行中)完全取决于datetime排序的位置。如果是这样,那应该可以使用row_number()和模2来解决(因为第二行(按顺序)是out记录)。也就是说,将行号模2为1的所有行与行号等于另一行的行号加1的行连接起来。

WITH cte
AS
(
SELECT date,
       time,
       row_number() OVER (ORDER BY date,
                                   time) rn;
       FROM elbat
)
SELECT cte1.date [arrival date],
       cte1.time [arrival time],
       cte2.date [leaving date],
       cte2.time [leaving time]
       FROM (SELECT cte.date,
                    cte.time,
                    cte.rn
                    FROM cte
                    WHERE cte.rn % 2 = 1) cte1
            LEFT JOIN cte cte2
                      ON cte2.rn = cte1.rn + 1;