【发布时间】:2018-11-15 23:31:02
【问题描述】:
我有两张桌子,一张是事件,另一张是剧集。 剧集有开始日期和结束日期,事件只有一个日期。 剧集和事件都有六种类型之一。
目前,我正在使用一些模糊逻辑在 Events 表上运行更新脚本,以将其 ID 字段设置为匹配的 Episode。它通过检查情节开始和结束之间的事件日期来做到这一点,两者都具有相同的类型,以及其他一些链接,如相同的用户等。
由于事件可以位于情节之外,或者具有不同的类型,我所做的是循环浏览一系列扩展日期范围(StartDate-1、-2 等),并循环浏览每个类型以寻找匹配项.
我一直在读到 while 循环效率不高,所以想知道是否有办法将此嵌套循环重写为 CTE 函数。
我使用的是 SQL Server 2012。 事件列表只是一个临时表,其中包含所有可能的类型以及循环顺序。
我目前的循环是:
WHILE @CurrBefore <= @Before and @CurrentAfter <= @After
BEGIN
SET @Row = 0
WHILE @Row <= @MaxRow
BEGIN
UPDATE P
SET P.ID = E.ID
FROM Event P
OUTER APPLY (SELECT TOP 1 E.Id, E.Type
FROM Episode E
WHERE E.User = P.User AND
E.Type = CASE WHEN @Row=0 THEN P.Event ELSE (SELECT Event FROM #EventList WHERE RN = @Row) END AND
P.Date BETWEEN E.StartDate-@CurrentBefore AND E.EndDate+@CurrentAfter
ORDER BY P.Date) E
WHERE P.ID = 0
INCREMENT @ROW CODE
END
INCREMENT @BEFORE/AFTER CODE
END
样本数据:
IF OBJECT_ID('tempdb..#EventList') IS NOT NULL
BEGIN
DROP TABLE #EventList
CREATE TABLE #EventList(Event Varchar(50), RN INT);
INSERT INTO #EventList SELECT 'A', 1
INSERT INTO #EventList SELECT 'B', 2
INSERT INTO #EventList SELECT 'C', 3
INSERT INTO #EventList SELECT 'D', 4
INSERT INTO #EventList SELECT 'E', 5
INSERT INTO #EventList SELECT 'F', 6
END
CREATE TABLE dbo.Episode ([ID] INT, [Start] DateTime, [End] DateTime, [Type] varchar(1), [User] INT)
INSERT INTO [dbo].Episode ([ID], [Start], [End], [Type],[User])
VALUES
(1, '2018-07-01 10:00', '2018-07-02 14:00', 'A',10),
(2, '2018-07-05 6:00', '2018-07-06 13:00', 'A',11),
(3, '2018-07-03 9:00', '2018-07-04 8:00', 'B',10),
(4, '2018-07-02 15:00', '2018-07-03 7:00', 'B',12),
(5, '2018-07-01 1:00', '2018-07-02 8:00', 'C',13),
(6, '2018-07-01 6:00', '2018-07-01 8:00', 'D',11)
CREATE TABLE dbo.Event ([ID] INT, [Date] DateTime, [Type] varchar(1), [User] INT)
INSERT INTO [dbo].Event ([ID], [Date], [Type],[User])
VALUES
(0, '2018-07-01 12:00', 'A',10),
(0, '2018-07-05 15:00', 'A',11),
(0, '2018-07-03 13:00', 'C',10),
(0, '2018-07-10 9:00', 'B',12),
(0, '2018-07-01 5:00', 'C',10),
(0, '2018-07-01 10:00', 'D',11)
预期结果,事件现在看起来像这样:
1 2018-07-01 12:00:00.000 A 10
2 2018-07-05 15:00:00.000 A 11
3 2018-07-03 13:00:00.000 C 10
0 2018-07-10 09:00:00.000 B 12
1 2018-07-01 05:00:00.000 C 10
6 2018-07-01 10:00:00.000 D 11
【问题讨论】:
-
请编辑问题并包含一些样本数据(一打或两行)以及您期望达到的最终结果。这个例子帮助大家理解所需的逻辑。
-
我想你也需要在这里解释一下“逻辑”;为什么第 5 个事件
(0, '2018-07-01 5:00', 'C',10)的 Episode.Id 为 1(仅用户匹配)而不是 5(日期/类型匹配)?另外你的while循环有UPDATE P——但P不匹配任何表/别名,你有CASE...THEN P.Event ELSE但只有你的临时表有一个名为Event的列——但如果临时表是P则 UPDATE 应该失败,因为临时表中没有ID列。 -
由于 p.User = e.User 的要求而匹配。时间和类型是灵活的。哎呀,在复制代码时一定错过了几个引用。这是我的脚本的一个更简单的版本,只有基本要求。我会修正参考资料。
-
基本上,代码所做的是将事件与剧集相匹配。该事件必须针对同一用户。事件有时可以在剧集中,也可以在剧集的任何一边。类型通常匹配,但有时可能不同。
-
我希望有一天,用于示例数据的 ddl+dml 会被如此广泛地使用,以至于我觉得没有必要为此投票赞成问题。但这不是这一天。
标签: sql-server tsql