【问题标题】:How to get Previous Value for Null Values如何获取空值的先前值
【发布时间】:2013-05-16 04:44:30
【问题描述】:

我的表中有以下数据。

   | Id  |  FeeModeId   |Name        |   Amount|
   ---------------------------------------------
   | 1   |  NULL        | NULL       |   20    |
   | 2   |  1           | Quarter-1  |   5000  |
   | 3   |  NULL        | NULL       |   2000  |    
   | 4   |  2           | Quarter-2  |   8000  |
   | 5   |  NULL        | NULL       |   5000  |
   | 6   |  NULL        | NULL       |   2000  |
   | 7   |  3           | Quarter-3  |   6000  |
   | 8   |  NULL        | NULL       |   4000  |

如何编写这样的查询以获得以下输出...

   | Id  |  FeeModeId   |Name        |   Amount|
   ---------------------------------------------
   | 1   |  NULL        | NULL       |   20    |
   | 2   |  1           | Quarter-1  |   5000  |
   | 3   |  1           | Quarter-1  |   2000  |    
   | 4   |  2           | Quarter-2  |   8000  |
   | 5   |  2           | Quarter-2  |   5000  |
   | 6   |  2           | Quarter-2  |   2000  |
   | 7   |  3           | Quarter-3  |   6000  |
   | 8   |  3           | Quarter-3  |   4000  |

【问题讨论】:

  • 什么版本的 SQL Server?
  • 谢谢,它很有帮助,但在我的情况下,以前的值差异不是固定的,有些时间 2 记录,有些时间 3,它可以是任何范围。
  • 看起来好像在 Oracle 中这个 could be done 和 LAST_VALUE ... IGNORE NULLS 但 SQL Server 不支持 IGNORE NULLS 选项。
  • @Randy "...使用 LAG 函数..." 如果您能发布一个示例,那就太好了。

标签: sql sql-server tsql sql-server-2012


【解决方案1】:

由于您使用的是 SQL Server 2012...这里有一个使用它的版本。它可能比其他解决方案更快,但您必须在数据上进行测试。

sum() over() 将执行由Id 排序的运行总和,当列中有值时添加1 并保留null 值的当前值。然后使用计算的运行总和将结果划分为first_value() over()。 Id 为运行总和生成的每个“组”行排序的第一个值具有您想要的值。

select T.Id,
       first_value(T.FeeModeId) 
          over(partition by T.NF 
               order by T.Id 
               rows between unbounded preceding and current row) as FeeModeId,
       first_value(T.Name)      
          over(partition by T.NS 
               order by T.Id 
               rows between unbounded preceding and current row) as Name,
       T.Amount
from (
     select Id,
            FeeModeId,
            Name,
            Amount,
            sum(case when FeeModeId is null then 0 else 1 end) 
              over(order by Id) as NF,
            sum(case when Name is null then 0 else 1 end) 
              over(order by Id) as NS
     from YourTable
     ) as T

SQL Fiddle

在 SQL Server 2012 之前可以使用的东西:

select T1.Id,
       T3.FeeModeId,
       T2.Name,
       T1.Amount
from YourTable as T1
  outer apply (select top(1) Name
               from YourTable as T2
               where T1.Id >= T2.Id and
                     T2.Name is not null
               order by T2.Id desc) as T2
  outer apply (select top(1) FeeModeId
               from YourTable as T3
               where T1.Id >= T3.Id and
                     T3.FeeModeId is not null
               order by T3.Id desc) as T3

SQL Fiddle

【讨论】:

    【解决方案2】:

    请尝试:

    select 
        a.ID,
        ISNULL(a.FeeModeId, x.FeeModeId) FeeModeId,
        ISNULL(a.Name, x.Name) Name,
        a.Amount
    from tbl a
    outer apply
    (select top 1 FeeModeId, Name 
        from tbl b 
        where b.ID<a.ID and 
            b.Amount is not null and 
            b.FeeModeId is not null and 
            a.FeeModeId is null order by ID desc)x
    

    或

    select 
        ID,
        ISNULL(FeeModeId, bFeeModeId) FeeModeId,
        ISNULL(Name, bName) Name,
        Amount
    From(
        select 
            a.ID , a.FeeModeId, a.Name, a.Amount, 
            b.ID bID, b.FeeModeId bFeeModeId, b.Name bName,
            MAX(b.FeeModeId) over (partition by a.ID) mx
        from tbl a left join tbl b on b.ID<a.ID
        and b.FeeModeId is not null
    )x 
    where bFeeModeId=mx or mx is null
    

    【讨论】:

      【解决方案3】:

      试试这个 -

      SELECT Id,
             CASE
               WHEN Feemodeid IS NOT NULL THEN
                Feemodeid
               ELSE
                (SELECT Feemodeid
                   FROM Table_Name t_2
                  WHERE t_2.Id = (SELECT MAX(Id)
                                    FROM Table_Name t_3
                                   WHERE t_3.Id < t_1.Id
                                     AND Feemodeid IS NOT NULL))
              END Feemodeid,
             CASE
               WHEN NAME IS NOT NULL THEN
                NAME
               ELSE
                (SELECT NAME
                   FROM Table_Name t_2
                  WHERE t_2.Id = (SELECT MAX(Id)
                                    FROM Table_Name t_3
                                   WHERE t_3.Id < t_1.Id
                                     AND NAME IS NOT NULL))
             END NAME,
             Amount
        FROM Table_Name t_1
      

      【讨论】:

        【解决方案4】:
        SELECT
          T.ID,
          ISNULL(T.FeeModeId, 
            (SELECT TOP 1 FeeModeId 
                FROM TableName AS T1 
                WHERE ID < T.ID AND FeeModeId IS NOT NULL 
                ORDER BY ID DESC)) AS FeeModeId,
          ISNULL(Name,
            (SELECT TOP 1 Name 
            FROM TableName 
            WHERE ID < T.ID AND Name IS NOT NULL 
            ORDER BY ID DESC)) AS Name,
          T.Amount
        FROM
          TableName AS T
        

        【讨论】:

          【解决方案5】:
          id  name
          1   toto
          2   NULL
          3   NULL
          4   titi
          5   NULL
          6   NULL
          7   tutu
          8   NULL
          9   NULL
          
          
          SELECT 
                 id_table
                 ,name
          FROM 
                 (
                       SELECT
                              T_01.id AS 'id_table'
                              ,max(T_02.id) AS 'id_name'
                       FROM
                              names AS T_01
                              cross join  
                              (
                                    SELECT
                                           id
                                           ,name
                                    FROM
                                           names
                                    WHERE
                                           name IS NOT NULL
                              ) AS T_02 
                       WHERE 
                              T_02.id <= T_01.id
                       GROUP BY 
                              T_01.id
                 ) AS tt02
                 left join names
                 ON names.id = tt02.id_name
          
          
          id_table    name
          1           toto
          2           toto
          3           toto
          4           titi
          5           titi
          6           titi
          7           tutu
          8           tutu
          9           tutu
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-09-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-09-18
            • 2020-11-13
            • 1970-01-01
            • 2018-04-06
            相关资源
            最近更新 更多