SQL:如何从不同的循环中获取结果
Posted
技术标签:
【中文标题】SQL:如何从不同的循环中获取结果【英文标题】:SQL: how to get the results from a varying loop 【发布时间】:2017-02-16 09:12:44 【问题描述】:要求:如果客户在 31 天内访问了多次,则仅包括第一次访问。例如,如果客户在 1 月 1 日访问,则包括 1 月 1 日的访问,但不包括 1 月 2 日至 1 月 31 日或之间发生的访问;然后(如果适用)包括在 2 月 1 日或之后发生的下一次访问。按时间顺序确定访问,包括每 31 天仅一次。
CustomerID VisitID VisitDate
1 1 1/1/2016
1 2 1/2/2016
1 3 1/31/2016
1 4 2/1/2016
1 5 7/1/2016
我需要客户在 31 天内的第一个条目,因此在上述情况下,我的结果查询应该只显示两个条目
CustomerID VisitID VisitDate
1 1 1/1/2016
1 4 2/1/2016
1 5 7/1/2016
有没有办法使用存储过程来完成这项工作。
声明@A 表 (CustomerID INT、VisitID INT、VisitDate DATE)
插入@A 值('1' ,'1' ,'1/15/2016') ,('1','2','2/2/2016') ; 有一个 AS (SELECT ROW_NUMBER() OVER (PARTITION BY CONVERT(NVARCHAR(2),DATEPART(MONTH,CONVERT(DATE,VisitDate))) 顺序按 VisitDate) row_id,CustomerID, VisitId,VisitDate FROM @A) SELECT CustomerID, VisitId,VisitDate FROM A WHERE row_id = 1
在上述脚本中,结果条目应仅为“1/15/2016”,因为“1/15/2016”和“2/2/2016”之间的日期差小于 31 天
您提供的 SP 适用于前两个条目,您能否帮助满足以下要求。我发誓这将是我的最后一个查询
-
('1/15/2016'), -- ----- (这是第一次有效访问)
('2/2/2016'), --(这是无效访问,因为此访问发生在第一次有效访问后的 31 天内)
('3/2/2016'), -- ----- (这是第二次有效访问,因为它发生在第一次有效访问后 31 天)
('3/4/2016'), --(这是无效访问,因为此访问发生在第二次有效访问后的 31 天内)
('3/15/2016'), --(这是无效访问,因为此访问发生在第 2 次有效访问后的 31 天内)
('7/5/2016'), -- ----- (这是第 3 次有效访问,因为它发生在第 2 次有效访问的 31 天后)
('8/1/2016'), -- (这是无效访问,因为本次访问
在第 3 次有效访问后的 31 天内发生)
('8/7/2016') -- ----- (这是第 4 次有效访问,因为此访问发生在第 3 次有效访问后的 31 天后)
【问题讨论】:
列 VisitDate' 数据类型?您使用的是哪个 dbms? (在日期/时间方面,许多产品远不符合 ANSI SQL。而且大多数产品都有自己的存储过程版本。) “31天期限”从什么开始?你能说得更具体一点吗?你也可以给我们看一些代码吗? 这里的要求是:如果客户在 31 天内有多次访问,则仅包括第一次访问。例如,如果客户在 1 月 1 日访问,则包括 1 月 1 日的访问,但不包括 1 月 2 日至 1 月 31 日或之间发生的访问;然后,如果适用,包括 2 月 1 日或之后发生的下一次访问。按时间顺序确定访问,每 31 天仅包括一次访问。 【参考方案1】:看看这个:
DECLARE @A TABLE (CustomerID INT,VisitID INT, VisitDate DATE)
DECLARE @B TABLE (CustomerID INT,VisitID INT, VisitDate DATE)
INSERT INTO @A VALUES('1','1','1/15/2016'), ('1','2','2/2/2016'),
('1','3','3/2/2016'), ('1','4','3/4/2016'), ('1','5','3/15/2016'),
('1','6','7/5/2016'), ('1','7','8/1/2016'), ('1','8','8/7/2016')
DECLARE @starter INT = 0,@counter INT=0,@CustomerID INT,@VisitID INT, @VisitDate DATE,@total INT = (SELECT COUNT(*) FROM @A)
WHILE(@starter<@total)
BEGIN
SELECT @CustomerID=A.CustomerID,@VisitID=A.VisitID,@VisitDate=A.VisitDate,
@counter = ISNULL((DATEDIFF(DAY,B.VisitDate,A.VisitDate)+@counter),0),@starter = @starter + 1
FROM @A A LEFT JOIN (SELECT VisitID+1 VisitID,VisitDate FROM @A
WHERE VisitID=@starter) B ON A.VisitID = B.VisitID WHERE A.VisitID = @starter+1
IF( @counter = 0 OR @counter > 31)
BEGIN
INSERT INTO @B SELECT @CustomerID,@VisitID,@VisitDate
SET @counter = 0
END
END
SELECT * FROM @A -- your table
SELECT * FROM @B -- output you desire :)
希望对您有所帮助。 :)
【讨论】:
非常感谢您的帮助,但是例如使用脚本,脚本会返回两个不满足我的要求的条目,因为两个日期之间的间隔小于 31 天,它应该只获取第一个条目,日期为 INSERT INTO @A VALUES('1' ,'1' ,'1/15/2016') ,('1' ,'2' ,'2/2/2016') 如果你能提供给我准确的样本数据,我会相应地给你准确的查询。 :) 并且脚本返回 3 个条目 '1'--------'1'---------'2016-01-01', '1'--------'4 '-------'2016-02-01', '1'-------'5'-------'2016-07-01' 我已经用你的 sql 查询和我的要求编辑了这个问题,你是救世主:) 编辑了答案,检查了第二个修改后的查询以及您将如何通过程序进行操作。 :) 完成,修改答案,就像你想要的那样。 :)以上是关于SQL:如何从不同的循环中获取结果的主要内容,如果未能解决你的问题,请参考以下文章