If Exists in the same SQL table 游标更新
If Exists in the same SQL table Cursor Update
我需要一些关于 SQL logic/language 的建议。我有一个游标,可以在 table 中循环浏览 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 语句,但我不确定 what/how 是否可以比较它是否存在。不可能说一个值是否存在,因为当然存在一个值,你只是从 table 中提取 customer_no/season 等。我怎么说是否存在一个值,但不包括我正在查看的值。
FETCH NEXT FROM db_cursor INTO @customer_no, @order_dt, @order_no
END
CLOSE db_cursor
DEALLOCATE db_cursor
END
如果我对你的问题的理解正确,你正在按降序检查客户订单,你去确定订单状态作为与客户最新订单的比较。
老实说,我不确定我是否理解您的要求,所以我的解决方案应该会给您提供您需要做的事情的要点。
首先不要使用游标。很少有使用它们的正当理由,它们既慢又贵。这个问题应该用 window 函数来解决。
Window 函数让您通过对分区执行聚合函数,从特定行查看结果集的 window。因此,例如,如果您想要具有相同客户 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
以下是 case 语句的工作原理:
- 仅当只有一个客户记录存在时才为真
- 如果存在多个客户记录,则为真,但年份等于最大年份
- 如果存在多个客户记录,则为真,但年份等于最大年份 - 1
- 如果存在多个客户记录,则为真,但年份小于最大年份 - 1。
我注释掉了派生列 DescOrderIdx
,因为虽然我的解决方案不需要它,但可能需要它来满足您的确切要求。如果不标记第一个订单,则应将检查该值是否不等于 1(最近的订单索引)作为附加条件。
我需要一些关于 SQL logic/language 的建议。我有一个游标,可以在 table 中循环浏览 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 语句,但我不确定 what/how 是否可以比较它是否存在。不可能说一个值是否存在,因为当然存在一个值,你只是从 table 中提取 customer_no/season 等。我怎么说是否存在一个值,但不包括我正在查看的值。
FETCH NEXT FROM db_cursor INTO @customer_no, @order_dt, @order_no
END
CLOSE db_cursor
DEALLOCATE db_cursor
END
如果我对你的问题的理解正确,你正在按降序检查客户订单,你去确定订单状态作为与客户最新订单的比较。
老实说,我不确定我是否理解您的要求,所以我的解决方案应该会给您提供您需要做的事情的要点。
首先不要使用游标。很少有使用它们的正当理由,它们既慢又贵。这个问题应该用 window 函数来解决。
Window 函数让您通过对分区执行聚合函数,从特定行查看结果集的 window。因此,例如,如果您想要具有相同客户 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
以下是 case 语句的工作原理:
- 仅当只有一个客户记录存在时才为真
- 如果存在多个客户记录,则为真,但年份等于最大年份
- 如果存在多个客户记录,则为真,但年份等于最大年份 - 1
- 如果存在多个客户记录,则为真,但年份小于最大年份 - 1。
我注释掉了派生列 DescOrderIdx
,因为虽然我的解决方案不需要它,但可能需要它来满足您的确切要求。如果不标记第一个订单,则应将检查该值是否不等于 1(最近的订单索引)作为附加条件。