如果存在于同一SQL表中游标更新

时间:2018-10-19 17:34:22

标签: sql-server tsql 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再次出现-但是年份不同,如果年份不是Year-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

1 个答案:

答案 0 :(得分:2)

如果我正确理解了您的问题,那么您将按照降序检查客户订单,以确认订单状态是否与该客户的最新订单相比较。

老实说,我有点不明白我是否了解您的要求,因此我的解决方案将为您提供所需要做的要点。

首先不要使用光标。很少有合理的理由使用它们,它们速度慢且价格昂贵。相反,应使用窗口函数解决此问题。

窗口函数使您可以通过在分区上执行聚合函数来从某一行查看结果集的窗口。因此,例如,如果您希望所有具有相同客户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(最新的订单索引)作为附加条件。