Если существует в той же таблице SQL Обновление курсора - PullRequest
0 голосов
/ 19 октября 2018

Мне нужен совет по логике / языку 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

1 Ответ

0 голосов
/ 19 октября 2018

Если я правильно понимаю вашу проблему, вы проверяете заказы клиентов в порядке убывания, который вы пошли, чтобы определить состояние заказов в сравнении с последним заказом для клиента.

Честно говоря, я немного сомневаюсь, понимаю ли я ваши требования, поэтому мое решение должно дать вам суть того, что вам нужно сделать.

Во-первых, не используйте пользовательские курсоры.Редко есть законная причина их использования, они медленные и дорогие.Вместо этого эту проблему следует решить с помощью оконных функций.

Оконные функции позволяют вам смотреть в окно вашего результирующего набора из определенной строки, выполняя агрегатную функцию над разделом.Например, если вы хотите указать минимальный год для всех строк с одинаковым идентификатором клиента, напишите 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. Будет толькобудет истинно, если существует только одна запись о клиенте
  2. Будет истинно, если существует несколько записей о клиентах, но год равен максимальному году
  3. Будет истинно, если существует несколько записей о клиентах, но год равен максимальному году- 1
  4. Будет истинно, если существует несколько записей о клиентах, но год меньше максимального года - 1.

Я закомментировал производный столбец DescOrderIdx, потому что пока его нетМне нужно мое решение, возможно, оно будет соответствовать вашим точным требованиям.Если первый ордер не должен быть помечен, то в качестве дополнительных критериев следует использовать проверку, если это значение не равно 1 (самый последний индекс ордера).

...