我非常基本的SQL用户。我知道基础知识和一些中级技能,但是我在编写这个查询时遇到了麻烦。
我有一个名为History的表,它包含特定数据的唯一条目。以下是该表格的简化版本:
+-------------------------+----+-----------+-------+
| Time | ID | ChangeNum | Value |
+-------------------------+----+-----------+-------+
| 2014-07-03 00:00:00.000 | 3 | 0 | A
+-------------------------+----+-----------+-------+
| 2014-10-02 00:00:00.000 | 3 | 1 | B
+-------------------------+----+-----------+-------+
| 2014-11-27 00:00:00.000 | 3 | 2 | C
+-------------------------+----+-----------+-------+
| 2015-01-15 00:00:00.000 | 3 | 3 | D
+-------------------------+----+-----------+-------+
| 2015-02-14 00:00:00.000 | 3 | 4 | E
+-------------------------+----+-----------+-------+
| 2015-09-02 00:00:00.000 | 3 | 5 | F
+-------------------------+----+-----------+-------+
| 2015-09-04 00:00:00.000 | 3 | 6 | G
+-------------------------+----+-----------+-------+
| 2016-09-13 00:00:00.000 | 3 | 7 | H
+-------------------------+----+-----------+-------+
| 2016-09-14 00:00:00.000 | 3 | 8 | I
+-------------------------+----+-----------+-------+
| 2017-02-12 00:00:00.000 | 3 | 9 | J
+-------------------------+----+-----------+-------+
| 2017-02-18 00:00:00.000 | 3 | 10 | K
+-------------------------+----+-----------+-------+
我需要做的是创建一个在这些日期范围之间生成数据的视图,同时保持其余值不变。例如,这是表格应该是什么样子的子集
+-------------------------+----+-----------+
| Time | ID | ChangeNum |
+-------------------------+----+-----------+
| 2014-07-03 00:00:00.000 | 3 | 0 |
+-------------------------+----+-----------+
| 2014-07-04 00:00:00.000 | 3 | 0 |
+-------------------------+----+-----------+
| 2014-07-05 00:00:00.000 | 3 | 0 |
+-------------------------+----+-----------+
| 2014-07-04 00:00:00.000 | 3 | 0 |
+-------------------------+----+-----------+
| truncated for readability ... |
+-------------------------+----+-----------+
| 2014-10-01 00:00:00.000 | 3 | 0 |
+-------------------------+----+-----------+
| 2014-10-02 00:00:00.000 | 3 | 1 |
+-------------------------+----+-----------+
我见过这样的帖子,我可以使用CTE生成日期范围,这很简单。但是,这涉及循环历史表中的结果集,获取日期范围的下限和上限(第一行的时间字段,然后是下一行的时间字段),然后生成这些行之间的数据。这可能比我看起来更容易,但我有点失落。我最初的想法是使用游标,但我不知道如何在表格中滞后/领先的情况下执行此操作。有帮助吗?感谢。
答案 0 :(得分:1)
这是一种有趣的方式,虽然我根据您的示例数据做出一些假设:
size = len(l)
idxl = [random.choice([j for j in range(size) if j != i]) for i in range(size)]
for idx in idxl:
# do something with the element at idx
修改更改了内容,以便它适用于所有ID,即使是使用不同的日期和ChangeNums:
--This is your current table
CREATE TABLE #TEST
(timefield datetime,
id int,
ChangeNum int)
INSERT INTO #TEST (TIMEFIELD, ID, CHANGENUM)
VALUES
('2014-07-03 00:00:00.000', 3, 0),
('2014-10-02 00:00:00.000', 3, 1),
('2014-11-27 00:00:00.000', 3, 2),
('2015-01-15 00:00:00.000', 3, 3),
('2015-02-14 00:00:00.000', 3, 4)
--This is your destination table
CREATE TABLE #TEST2
(timefield datetime,
id int,
ChangeNum int)
--This is where we INSERT from your source to destination table
DECLARE @TIMEFIELD datetime = '2014-07-03 00:00:00.000' --Your start date
DECLARE @ChangeNum int = 0 --Starting ChangeNum
WHILE @TIMEFIELD <= '2015-02-14 00:00:00.000' --Your end date
BEGIN
INSERT INTO #TEST2
SELECT @TIMEFIELD, 3, @ChangeNum;
SET @TIMEFIELD = DATEADD(DD, 1, @TIMEFIELD);
IF EXISTS (SELECT * FROM #TEST WHERE TIMEFIELD = @TIMEFIELD)
BEGIN
SET @ChangeNum = (SELECT ChangeNum FROM #TEST WHERE TIMEFIELD = @TIMEFIELD)
--This part can be modified to account for more columns
END
END
SELECT * FROM #TEST2 --The new table
答案 1 :(得分:0)
这很有趣。正如肖恩所说,你需要一个计数表或者我的话需要一个日期表。 This is where I got the Dates table from.如果两次更改在同一天进行,则不会考虑将会发生什么。我还缩短了时间范围,使测试更容易。这确实会导致返回多个ID。
CREATE TABLE #test (ID INT, ChangeNum INT, [Value] varchar(1), [Time] datetime);
DECLARE @StartDate datetime
, @CutoffDate datetime;
INSERT INTO #test ([time], ID, ChangeNum, [Value])
VALUES
('2011-07-03 00:00:00.000', 3, 0, 'A'),
('2011-07-10 00:00:00.000', 3, 1, 'B'),
('2011-07-15 00:00:00.000', 3, 2, 'C'),
('2011-07-01 00:00:00.000', 2, 0, 'Q'),
('2011-07-06 00:00:00.000', 2, 1, 'R'),
('2011-08-03 00:00:00.000', 2, 2, 'S');
SELECT @StartDate = MIN([Time])
,@CutoffDate = MAX([time])
FROM #test;
WITH Dates
AS (SELECT d
FROM (
SELECT d = DATEADD(DAY, rn - 1, @StartDate)
FROM (SELECT TOP (DATEDIFF(DAY, @StartDate, @CutoffDate)) rn = ROW_NUMBER() OVER (
ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
ORDER BY s1.[object_id]
) AS x
) AS y
)
,ChangeRanges
AS (
SELECT ID
, [Time] BEGIN_DATE
, CASE WHEN LEAD ([Time], 1,0) OVER (PARTITION BY ID ORDER BY ID, [time]) = '1900-01-01 00:00:00.000' THEN [Time]
ELSE DATEADD(DAY, -1, LEAD ([Time], 1,0) OVER (PARTITION BY ID ORDER BY ID, [time])) END END_DATE
, ChangeNum
FROM #test
)
SELECT d.d [DATE]
,cr.ID
,cr.ChangeNum
FROM ChangeRanges cr
JOIN Dates d ON d.d >= cr.BEGIN_DATE AND d.d <= cr.END_DATE
WHERE ID = 3
GROUP BY cr.ID, d.d, cr.ChangeNum
ORDER BY cr.ID, d.d
DROP TABLE #test