【问题标题】:SQL: How to fill the rows between 2 specific rows with the same value?SQL:如何用相同的值填充 2 个特定行之间的行?
【发布时间】:2017-02-24 03:29:44
【问题描述】:

我需要在两个“AL”或两个“MX”之间用“-”填充/替换行,其值为“AL”或“MX”,具体取决于“-”出现的位置。出于本示例的目的,我只使用了 2 个“uid”(实际上我有更多的 uid)。此外,该表在 ASC 中按 uid 和 code_date 列排序

为了便于理解,我有这张表:

但我想要这样的东西:

我正在使用 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

【问题讨论】:

    标签: sql sql-server tsql sql-server-2008-r2 common-table-expression


    【解决方案1】:
    /* 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
    

    【讨论】:

    • @user7020195 这个解决方案没有解决我的问题。我正在尝试用任何一个填充相同值“AL”或“MX”之间的“-”值。
    • @user7020195 很抱歉!解决方案是正确的。我最初没有正确检查。谢谢
    【解决方案2】:
    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 <> ''
    

    【讨论】:

      【解决方案3】:

      对于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;
      

      【讨论】:

        猜你喜欢
        • 2022-06-15
        • 1970-01-01
        • 1970-01-01
        • 2019-01-05
        • 2014-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多