SQL: Как заполнить строки между двумя конкретными строками одним и тем же значением?

Мне нужно заполнить / заменить строки "-" между двумя "AL" ИЛИ двумя "MX" со значением "AL" или "MX" в зависимости от того, где появляется "-". Для целей этого примера я использую только 2 uid (на самом деле у меня больше uid). Кроме того, таблица упорядочена по столбцам uid и code_date в ASC

Для простоты понимания у меня есть эта таблица:

но я хотел бы иметь что-то вроде этого:

Я использую SQL Server 2008. Любое предложение о том, как я могу добиться этого???

Я создал таблицу со следующим кодом:

DECLARE @Customers TABLE
    (uid bigint,
     code_date date,
     Value nchar(10)
    ) 

INSERT  INTO @Customers
VALUES  (1591, '2016-08-01', ''),
    (1591, '2016-08-02', ''),
    (1591, '2016-08-03', 'AL'),
    (1591, '2016-08-04', '-'),
    (1591, '2016-08-05', '-'),
    (1591, '2016-08-06', '-'),
    (1591, '2016-08-07', '-'),
    (1591, '2016-08-08', '-'),
    (1591, '2016-08-09', 'AL'),
    (1591, '2016-08-10', ''),
    (1591, '2016-08-11', 'AL'),
    (1591, '2016-08-12', ''),
    (1082, '2016-02-01', ''),
    (1082, '2016-02-02', ''),
    (1082, '2016-02-03', ''),
    (1082, '2016-02-04', ''),
    (1082, '2016-02-05', 'MX'),
    (1082, '2016-02-06', '-'),
    (1082, '2016-02-07', '-'),
    (1082, '2016-02-08', '-'),
    (1082, '2016-02-09', '-'),
    (1082, '2016-02-10', '-'),
    (1082, '2016-02-11', '-'),
    (1082, '2016-02-12', 'MX');

    SELECT * FROM @Customers ORDER BY uid, code_date ASC

3 ответа

Решение
declare @x varchar(1000) = ''

update @Customers
set  @x = value = (case when @x <> '' and value not in ('-',@x) then '' else @x end) + (case when value = '-' then '' when value = @x then ''  else value end)
where value <> ''
/* Test Data & Table */
DECLARE @Customers TABLE
    (Dates datetime,
     Customer integer,
     Value integer) 

    INSERT  INTO @Customers
    VALUES  ('20100101', 1, 12),
        ('20100101', 2, NULL),
        ('20100101', 3, 32),
        ('20100101', 4, 42),
        ('20100101', 5, 15),
        ('20100102', 1, NULL),
        ('20100102', 2, NULL),
        ('20100102', 3, 39),
        ('20100102', 4, NULL),
        ('20100102', 5, 16),
        ('20100103', 1, 13),
        ('20100103', 2, 24),
        ('20100103', 3, NULL),
        ('20100103', 4, NULL),
        ('20100103', 5, 21),
        ('20100104', 1, 14),
        ('20100104', 2, NULL),
        ('20100104', 3, NULL),
        ('20100104', 4, 65),
        ('20100104', 5, 23) ;

/* CustCTE - This gives us a RowNum to allow us to build the recursive CTE CleanCust */
WITH    CustCTE
          AS (SELECT    Customer,
                        Value,
                        Dates,
                        ROW_NUMBER() OVER (PARTITION BY Customer ORDER BY Dates) RowNum
              FROM      @Customers),

/* CleanCust - A recursive CTE. This runs down the list of values for each customer, checking the Value column, if it is null it gets the previous non NULL value.*/
        CleanCust
          AS (SELECT    Customer,
                        ISNULL(Value, 0) Value, /* Ensure we start with no NULL values for each customer */
                        Dates,
                        RowNum
              FROM      CustCte cur
              WHERE     RowNum = 1
              UNION ALL
              SELECT    Curr.Customer,
                        ISNULL(Curr.Value, prev.Value) Value,
                        Curr.Dates,
                        Curr.RowNum
              FROM      CustCte curr
              INNER JOIN CleanCust prev ON curr.Customer = prev.Customer
                                           AND curr.RowNum = prev.RowNum + 1)

/* Update the base table using the result set from the recursive CTE */
    UPDATE trg
    SET Value = src.Value
    FROM    @Customers trg
    INNER JOIN CleanCust src ON trg.Customer = src.Customer
                                AND trg.Dates = src.Dates

/* Display the results */
SELECT * FROM @Customers

Для select запрос, просто используйте outer apply:

select t.*, coalesce(t.value, t2.value) as new_value
from t outer apply
     (select top 1 t2.*
      from t t2
      where t2.uid = t.uid and t2.code_date < t.code_date and t2.value is not null
      order by t2.code_date desc
     ) t2;

Вы можете использовать аналогичную логику в update,

Как update, это было бы:

update t
    set value = t2.new_value
    from t outer apply
         (select top 1 t2.*
          from t t2
          where t2.uid = t.uid and t2.code_date < t.code_date and t2.value is not null
          order by t2.code_date desc
         ) t2
    where t.value is null;
Другие вопросы по тегам