【问题标题】:SQL filling in dates and dataSQL 填写日期和数据
【发布时间】:2016-12-20 18:17:28
【问题描述】:

我有一个数据表和一个日历表。我需要填补空白,以便每天有一行。我需要填写日期以及使用先前的有效值进行序列和操作。 NULL 是有效的操作类型。我已经接近了,但 NULLS 一直在搞砸我的结果。

我正在使用 SQL Server 2014。非常感谢您的帮助。

数据:

ID | Sequence|                Date| Action|
---|---------|--------------------|-------|
A  |       1 |  4/5/2016 12:09:23 |  yield|
A  |       2 |  4/7/2016 12:25:16 |   stop|
A  |       3 |  4/12/2016 11:25:42|   NULL|
A  |       4 |  4/18/2016 11:25:42|     go|
B  |       1 |  2/17/2016 14:15:10|  yield|
B  |       2 |  3/1/2016 7:56:37  |   stop|
B  |       3 |  4/1/2016 9:24:46  |     go|
B  |       4 |  5/4/2016 12:25:16 |   exit|

日历:

DateKey |                Date|
--------|--------------------|
2838    |   4/6/2016 0:00:00 |
2839    |   4/7/2016 0:00:00 |
2840    |   4/8/2016 0:00:00 |
2841    |   4/9/2016 0:00:00 |
2842    |  4/10/2016 0:00:00 |
2843    |  4/11/2016 0:00:00 |
2844    |  4/12/2016 0:00:00 |
2845    |  4/13/2016 0:00:00 |
2846    |  4/14/2016 0:00:00 |
2847    |  4/15/2016 0:00:00 |
2848    |  4/16/2016 0:00:00 |
2849    |  4/17/2016 0:00:00 |
2850    |  4/18/2016 0:00:00 |

期望的结果:

ID  | Sequence|                Date|    Action|
----|---------|--------------------|----------|
A   |        1|   4/5/2016 12:09:23|     yield|
A   |        1|    4/6/2016 0:00:00|     yield|
A   |        2|   4/7/2016 12:25:16|      stop|
A   |        2|    4/8/2016 0:00:00|      stop|
A   |        2|    4/9/2016 0:00:00|      stop|
A   |        2|   4/10/2016 0:00:00|      stop|
A   |        2|   4/11/2016 0:00:00|      stop|
A   |        3|  4/12/2016 10:35:34|      NULL|
A   |        3|   4/13/2016 0:00:00|      NULL|
A   |        3|   4/14/2016 0:00:00|      NULL|
A   |        3|   4/15/2016 0:00:00|      NULL|
A   |        3|   4/16/2016 0:00:00|      NULL|
A   |        3|   4/17/2016 0:00:00|      NULL|
A   |        4|   4/18/2016 11:25:4|        go|

TSQL 建立测试表:

IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME =     'Data') 
    DROP TABLE Data;

CREATE TABLE Data (ID varchar(20), SEQ INT, Date datetime, Action     varchar(20));

INSERT INTO data (ID, SEQ, Date, Action) VALUES
('A', 1, '4/5/2016 12:09:23','yield' ),
('A', 2, '4/7/2016 12:25:16','stop' ),
('A', 3, '4/12/2016 11:25:42','NULL' ),
('A', 4, '4/18/2016 11:25:42','go' )



IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME =     'Calendar')
    DROP TABLE Calendar;

CREATE TABLE Calendar (DateKey int, Date datetime);

INSERT INTO Calendar (DateKey, Date) VALUES
('2838','4/6/2016 0:00:00'),
('2839','4/7/2016 0:00:00' ),
('2840', '4/8/2016 0:00:00' ),
('2841', '4/9/2016 0:00:00' ),
('2842', '4/10/2016 0:00:00'),
('2843', '4/11/2016 0:00:00' ),
('2844', '4/12/2016 0:00:00' ),
('2845', '4/13/2016 0:00:00' ),
('2846', '4/14/2016 0:00:00' ),
('2847', '4/15/2016 0:00:00'),
('2848', '4/16/2016 0:00:00' ),
('2849', '4/17/2016 0:00:00' ),
('2850', '4/18/2016 0:00:00' )

【问题讨论】:

  • 我认为使用代码而不是 SQL 会更容易做到这一点
  • 抱歉,我对标签感到满意...如果可以的话,我会编写代码...
  • 虽然我没有时间为您编写查询,但我会为您指明正确的方向:您可以执行类似 select * from table1 t1 left join table2 t2 ON 之类的操作t1.dDate
  • 我建议通读这个。虽然它不能完全解决您的问题,但它可以帮助您构建所需的主子查询。 stackoverflow.com/questions/19432913/…

标签: sql-server date datetime


【解决方案1】:

这个 SQL 命令呢?

SELECT A.[ID]
      ,A.[SEQ]
      ,ISNULL(A.[Date], B.[Date]) AS 'DATE'
      ,A.[Action]
FROM DATA A FULL JOIN CALENDAR B 
     ON cast(A.[Date] as DATE) = cast(B.[Date] as DATE)
ORDER BY B.[date] ASC

FULL JOIN 选项的结果:

ID  | SEQ | DATE                    | Action|
----|-----|-------------------------|-------|
A   | 1   | 2016-04-05 12:09:23.000 |yield  |
NULL| NULL| 2016-04-06 00:00:00.000 |NULL   |
A   | 2   | 2016-04-07 12:25:16.000 |stop   |
NULL| NULL| 2016-04-08 00:00:00.000 |NULL   |
NULL| NULL| 2016-04-09 00:00:00.000 |NULL   |
NULL| NULL| 2016-04-10 00:00:00.000 |NULL   |
NULL| NULL| 2016-04-11 00:00:00.000 |NULL   |
A   | 3   | 2016-04-12 11:25:42.000 |NULL   |
NULL| NULL| 2016-04-13 00:00:00.000 |NULL   |
NULL| NULL| 2016-04-14 00:00:00.000 |NULL   |
NULL| NULL| 2016-04-15 00:00:00.000 |NULL   |
NULL| NULL| 2016-04-16 00:00:00.000 |NULL   |
NULL| NULL| 2016-04-17 00:00:00.000 |NULL   |
A   | 4   | 2016-04-18 11:25:42.000 |go     |

【讨论】:

  • 不幸的是,这并没有为每一天创建一行
  • 我认为他想做的恰恰相反。 FROM Calendar LEFT JOIN Data 而不是 FROM Data LEFT JOIN Calendar(或将 LEFT JOIN 更改为 RIGHT JOIN,但我不推荐它。Right JOINS 是愚蠢的。它们在 99.99% 的时间里都是反转的 LEFT JOIN,就像它会处于这种情况)。但是,这将使日历中的天数与具有 NULL 值的数据中的天数不匹配。它不会得到以前的值。那是容易的部分。获取空天的先前值是较难的部分。查看我在您的第一篇文章中的评论,了解解决方案。
  • 我实际上得到了要填写的日期,但正如你提到的,困难的部分是获取以前的值。我见过的大多数解决方案都使用 'top 1' / order by 的变体与 'where action is not null' 结合使用(这就是它让我想到的地方)。
  • 是的,我很难为你测试它。我们有 MySQL 在工作,语法上有几个主要差异。我曾经在 MS SQL Server 下开发,但我不会写一个我什至无法测试的查询 lol。但就像我说的那样,我正在考虑使用 = 条件进行连接,但话又说回来,您确实希望在日历表中的日期之前从数据表中获取最新状态。这可能会变成一个相当复杂的查询,但它绝对可行,我过去做过几个。这些通常会变成带有几个子查询级别的查询。
  • 感谢大家的反馈。我使用 FULL JOIN 改进了脚本并编写了我的测试结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-16
相关资源
最近更新 更多