SQL根据日期时间从多个表中进行选择

时间:2014-12-19 17:34:44

标签: sql sql-server join datetime2

我正在编写一个脚本来分析SQL Server 2008数据库中数千个表中包含的一些数据。

为简单起见,表格可以分为4-8个半相关表格。通过半关联,我的意思是它们是同一项的数据集合,但它们没有任何实际的SQL关系。每个表都包含一个日期时间戳(datetime2数据类型),值(可以是bitintfloat,具体取决于具体项目),以及其他一些目前不感兴趣的专栏。日期时间标记在几秒钟内每15分钟(在四分之一小时内)设置;然而,并非所有数据都是同时准确记录的......

例如:

TABLE1:

TIMESTAMP                 VALUE
2014-11-27 07:15:00.390      1
2014-11-27 07:30:00.390      0
2014-11-27 07:45:00.373      0
2014-11-27 08:00:00.327      0

TABLE2:

TIMESTAMP                 VALUE
2014-11-19 08:00:07.880      0
2014-11-19 08:15:06.867      0.0979999974370003
2014-11-19 08:30:08.593      0.0979999974370003
2014-11-19 08:45:07.397      0.0979999974370003

表3

TIMESTAMP                 VALUE
2014-11-27 07:15:00.390        0
2014-11-27 07:30:00.390        0
2014-11-27 07:45:00.373        1
2014-11-27 08:00:00.327        1

如您所见,并非所有表都以相同的季度TIMESTAMP开头。基本上,我所追求的是一个查询,它将从3个表中最早的TIMESTAMP开始,每隔15分钟为3个表中的每个表返回VALUE。对于给出的示例,我想从2014-11-27 07:15开始(不关心秒......因此,需要允许时间戳为+ - 1分钟左右)。当没有特定TIMESTAMP的记录时,返回NULL值是可以的。因此,我列出的示例的查询将返回如下内容:

TIMESTAMP                 VALUE1   VALUE2             VALUE3
2014-11-27 07:15           1    NULL                  0
2014-11-27 07:30           0    NULL                  0
2014-11-27 07:45           0    NULL                  1
2014-11-27 08:00           0    NULL                  1
...
2014-11-19 08:00           0         0                        1
2014-11-19 08:15           0         0.0979999974370003       0
2014-11-19 08:30           0         0.0979999974370003       0
2014-11-19 08:45           0         0.0979999974370003       0

我希望这是有道理的。任何帮助/指针/指导将不胜感激。

3 个答案:

答案 0 :(得分:0)

使用Full Outer Join

SELECT COALESCE(a.[TIMESTAMP], b.[TIMESTAMP], c.[TIMESTAMP]) [TIMESTAMP],
       Isnull(Max(a.VALUE), 0)                               VALUE1,
       Max(b.VALUE)                                          VALUE2,
       Isnull(Max(c.VALUE), 0)                               VALUE3
FROM   TABLE1 a
       FULL OUTER JOIN TABLE2 b
                    ON CONVERT(SMALLDATETIME, a.[TIMESTAMP]) = CONVERT(SMALLDATETIME, b.[TIMESTAMP])
       FULL OUTER JOIN TABLE3 c
                    ON CONVERT(SMALLDATETIME, a.[TIMESTAMP]) = CONVERT(SMALLDATETIME, c.[TIMESTAMP])
GROUP  BY COALESCE(a.[TIMESTAMP], b.[TIMESTAMP], c.[TIMESTAMP])
ORDER  BY [TIMESTAMP] DESC 

答案 1 :(得分:0)

我要做的第一件事就是将时间戳标准化为分钟。您可以通过更新现有列

来执行此操作
UPDATE TABLENAME
  SET TIMESTAMP = dateadd(minute,datediff(minute,0,TIMESTAMP),0)

或在新专栏中

ALTER TABLE TABLENAME ADD COLUMN NORMTIME DATETIME;

UPDATE TABLENAME
  SET NORMTIME = dateadd(minute,datediff(minute,0,TIMESTAMP),0)

有关地板日期的详细信息,请参阅此帖:Floor a date in SQL server


下一步是创建一个包含您希望看到的所有时间戳(规范化)的表 - 每行15个 - 一个。让我的示例调用此表TIME_PERIOD和列EVENT_TIME(无论你想要什么,都可以调用它)。

有很多方法可以使这样的表递归CTE,ROW_NUMBER(),甚至蛮力。我把那部分留给你了。


现在问题很简单,选择左连接和有效值的过滤器,如下所示:

SELECT TP.EVENT_TIME, a.VALUE as VALUE1, b.VALUE as VALUE2, c.VALUE as VALUE3
FROM  TIME_PERIOD TP
LEFT JOIN TABLE1 a ON a.[TIMESTAMP] = TP.EVENT_TIME
LEFT JOIN TABLE2 b ON b.[TIMESTAMP] = TP.EVENT_TIME
LEFT JOIN TABLE3 c ON c.[TIMESTAMP] = TP.EVENT_TIME
WHERE COALESCE(a.[TIMESTAMP], b.[TIMESTAMP], c.[TIMESTAMP]) is not null
ORDER  BY TP.EVENT_TIME DESC 

如果它们是不同的类型,那么它可能会变得更复杂,所以你总是可以使用它(它不如合并但总是有效):

WHERE a.[TIMESTAMP] IS NOT NULL OR
      b.[TIMESTAMP] IS NOT NULL OR
      c.[TIMESTAMP] IS NOT NULL

答案 2 :(得分:0)

这是NoDisplayName的答案的更新版本,可以满足您的需求。它适用于SQL 2012,但您可以使用一系列其他函数替换DATETIMEFROMPARTS函数以获得相同的结果。

;WITH 
NewT1 as (
SELECT DATETimeFROMPARTS( DATEPART(year,Timestamp) , DATEPART(month,timestamp) , datepart(day,timestamp),datepart(hour,timestamp), datepart(minute,timestamp),0,0 ) as TimeStamp, Value
FROM Table1),
NewT2 as (
SELECT DATETimeFROMPARTS( DATEPART(year,Timestamp) , DATEPART(month,timestamp) , datepart(day,timestamp),datepart(hour,timestamp), datepart(minute,timestamp),0,0 ) as TimeStamp, Value
FROM Table2),
NewT3 as (
SELECT DATETimeFROMPARTS( DATEPART(year,Timestamp) , DATEPART(month,timestamp) , datepart(day,timestamp),datepart(hour,timestamp), datepart(minute,timestamp),0,0 ) as TimeStamp, Value
FROM Table3)
SELECT COALESCE(a.[TIMESTAMP], b.[TIMESTAMP], c.[TIMESTAMP]) [TIMESTAMPs],
       Isnull(Max(a.VALUE), 0)                            VALUE1,
       Isnull(Max(b.VALUE), 0)                                       VALUE2,
       Isnull(Max(c.VALUE), 0)                                       VALUE3
FROM   NewT1 a
       FULL OUTER JOIN NewT2 b
                    ON a.[TIMESTAMP] = b.[TIMESTAMP]
       FULL OUTER JOIN TABLE3 c
                    ON a.[TIMESTAMP] = b.[TIMESTAMP]
GROUP  BY COALESCE(a.[TIMESTAMP], b.[TIMESTAMP], c.[TIMESTAMP])
ORDER  BY [TIMESTAMPs]