sql-server - 如果同一个SQL表中存在游标更新

标签 sql-server t-sql if-statement cursor exists

我需要一些有关 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

以下是案例陈述的工作原理:

  1. 仅当仅存在一条客户记录时才为真
  2. 如果存在多个客户记录,但年份等于最大年份,则为 true
  3. 如果存在多个客户记录,但年份等于最大年份 - 1,则为 true
  4. 如果存在多个客户记录,但年份小于最大年份 - 1,则为 true。

我注释掉了派生列 DescOrderIdx,因为虽然我的解决方案不需要它,但可能需要它来满足您的确切要求。如果不标记第一个订单,则应检查该值是否不等于 1(最近的订单索引)作为附加条件。

关于sql-server - 如果同一个SQL表中存在游标更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52897375/

相关文章:

sql - 如何找到两个数据库之间的差异?

sql - 创建触发器以将列值插入到同一表的其他列 SQL Server 2005

sql - 帮助 PIVOT

.net - SQL Azure 上的全文搜索

sql-server - 如何将动态SQL的结果存储在变量中?

c - 避免大量的 if-else 检查

javascript,在 if 语句中组合 AND、OR

SQL Server - 如何在表中查找十六进制字符

python - Pandas :依赖于另一个值的列

sql-server - ConnectionString 未在 SSIS 集成项目中加密