我需要一些有关 SQL 逻辑/语言的建议。我有一个游标,可以在表中的数千个 year + customer_id + order_no
组合中循环。
数据样本
year customer_id order_no markerA markerB markerC MarkerD
2018 32329 523142
2018 32329 523243
2018 39566 523508
2018 42352 523214
2017 17675 470537
2017 21486 479414
2017 39566 479038
2017 42352 479220
等等
我需要我的逻辑做的是提取上面的 customer_id + Year + order_no 组合的值
如果没有再出现 customer_no(在初始拉取之后),则 MarkerA - 'Y'。
但是,如果 customer_no 再次出现 - 如果该年份与初始拉取中的年份相同,则 MarkerB -'Y'。
但是,如果 customer_no 再次出现 - 但年份不同,请进一步检查如果年份是年份 - 1,则 MarkerC -'Y'。
如果 customer_no 再次出现 - 但年份不同,如果年份不是年份 - 1,但其他地方确实存在年份 2 或更高版本的行,则进一步检查 MarkerD -'Y'。
declare @order_year int
declare @customer_id int
declare @order_dt datetime
declare @order_no int
BEGIN
DECLARE db_cursor CURSOR FOR
Select distinct year, customer_id, order_dt, order_no From #Compare_Data
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @order_year, @customer_no, @order_dt, @order_no
WHILE @@FETCH_STATUS = 0
BEGIN
...我知道我需要一系列 IF 语句,但我不确定如果存在的话要比较什么/如何比较。不可能说某个值是否存在,因为当然存在一个值,您只是从表中提取了 customer_no/season 等。如果存在一个值(不包括我正在查看的值),我该怎么说?
FETCH NEXT FROM db_cursor INTO @customer_no, @order_dt, @order_no
END
CLOSE db_cursor
DEALLOCATE db_cursor
END
最佳答案
如果我正确理解您的问题,您正在按降序检查客户订单,以便与客户的最新订单进行比较来确定订单状态。
老实说,我对是否理解您的要求有点怀疑,所以我的解决方案应该让您了解您需要做什么的要点。
首先不要使用光标。很少有正当理由使用它们,它们速度慢且昂贵。这个问题应该用窗口函数来解决。
窗口函数允许您通过在分区上执行聚合函数来从特定行查看结果集的窗口。因此,例如,如果您想要具有相同客户 ID 的所有行的最小年份,则可以编写 MIN([Year]) OVER (PARTITION BY CustomerId)
。
以下是尝试解决您的问题。我可以想象您将必须调整 CASE
表达式以适合您的确切标准。
-- Setup test data
DECLARE @CompareData TABLE ( [Year] INT, CustomerId INT, OrderNo INT );
INSERT INTO @CompareData
VALUES
(2018, 32329, 523142),
(2018, 32329, 523243),
(2018, 39566, 523508),
(2018, 42352, 523214),
(2017, 17675, 470537),
(2017, 21486, 479414),
(2017, 39566, 479038),
(2017, 42352, 479220),
(2016, 42352, 479220);
-- solution
WITH src AS (
SELECT *
--, ROW_NUMBER() OVER
-- (PARTITION BY CustomerId ORDER BY Year DESC, OrderNo DESC) DescOrderIdx
, COUNT(CustomerId) OVER (PARTITION BY CustomerId) CustCount
, MIN([Year]) OVER (PARTITION BY CustomerId) MinYear
, MAX([Year]) OVER (PARTITION BY CUstomerId) MaxYear
FROM @CompareData
)
SELECT [Year], CustomerId, OrderNo
, CASE WHEN CustCount = 1 THEN 'Y' ELSE '' END [MarkerA]
, CASE WHEN CustCount > 1 AND [Year] = MaxYear THEN 'Y' ELSE '' END [MarkerB]
, CASE WHEN CustCount > 1 AND [Year] = MaxYear - 1 THEN 'Y' ELSE '' END [MarkerC]
, CASE WHEN CustCount > 1 AND [Year] < MaxYear - 1 THEN 'Y' ELSE '' END [MarkerD]
FROM src
以下是案例陈述的工作原理:
- 仅当仅存在一条客户记录时才为真
- 如果存在多个客户记录,但年份等于最大年份,则为 true
- 如果存在多个客户记录,但年份等于最大年份 - 1,则为 true
- 如果存在多个客户记录,但年份小于最大年份 - 1,则为 true。
我注释掉了派生列 DescOrderIdx
,因为虽然我的解决方案不需要它,但可能需要它来满足您的确切要求。如果不标记第一个订单,则应检查该值是否不等于 1(最近的订单索引)作为附加条件。
关于sql-server - 如果同一个SQL表中存在游标更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52897375/