查询以保留最新的非零值

时间:2021-02-16 20:32:59

标签: sql-server tsql sql-server-2016

我正在使用 SQL Server 2016 并有一个包含以下数据的表:

<头>
PlaySeq TransMaxValue
1 250
2 500
3 0
4 400
5 0
6 300
7 500
8 0
9 0

我正在尝试构建一个向该数据集添加列 TransMaxValueContd 的查询。
TransMaxValueContd 列应保留在列 TransMaxValue 中遇到的最后一个非零值。
订购由PlaySeq完成。

我预期的查询结果如下:

<头>
PlaySeq TransMaxValue TransMaxValueContd
1 250 250
2 500 500
3 0 500
4 400 400
5 0 400
6 300 300
7 500 500
8 0 500
9 0 500

我一直在使用像 LAST_VALUE()LAG() 这样的窗口函数,但似乎无法得到正确的结果。
也许我把它复杂化了。
有人知道怎么做吗?

ps:我只是在寻找查询。无需修改源表。

编辑:添加了一个尝试失败的 SQLFiddle example,即:

SELECT a.PlaySeq, 
       a.TransMaxValue,
       IIF(ISNULL(LAG(a.TransMaxValue,1) OVER (ORDER BY a.PlaySeq), a.TransMaxValue) = a.TransMaxValue, a.TransMaxValue, LAG(a.TransMaxValue,1) OVER (ORDER BY a.PlaySeq)) AS TransMaxValueContd
FROM   myTable AS a;

编辑:感谢您的所有回答,提供了新的有用见解!
我最终使用了这个,灵感来自 answerSteveC

SELECT  a.PlaySeq, 
        a.TransMaxValue,
        (SELECT     TOP 1 x.TransMaxValue 
         FROM       myTable AS x 
         WHERE      x.PlaySeq <= a.PlaySeq 
         AND        x.TransMaxValue != 0 
         ORDER BY   x.PlaySeq DESC) AS TransMaxValueContd
FROM    myTable AS a;

4 个答案:

答案 0 :(得分:2)

一种简单的方法是使用 OUTER APPLYSELECT TOP(1)。像这样

select m.PlaySeq, m.[TransMaxValue],
       case when m.[TransMaxValue]=0 
            then oa.TransMaxValue 
            else m.TransMaxValue end TransMaxValueContd
from myTable m
     outer apply (select top(1) mm.[TransMaxValue]
                  from myTable mm
                  where m.PlaySeq>mm.PlaySeq
                        and mm.[TransMaxValue]>0
                  order by mm.PlaySeq desc) oa;
PlaySeq TransMaxValue   TransMaxValueContd
1       250             250
2       500             500
3       0               500
4       400             400
5       0               400
6       300             300
7       500             500
8       0               500
9       0               500

答案 1 :(得分:1)

也许这会有所帮助:

DECLARE @Tab TABLE(PlaySeq INT, TransMaxValue INT)
INSERT @Tab
VALUES(1,250),(2,500),(3,0),(4,400),(5,0)
     ,(6,300),(7,500),(8,0),(9,0)

SELECT PlaySeq, 
       TransMaxValue,
       FIRST_VALUE(TransMaxValue) OVER(PARTITION BY Grp ORDER BY PlaySeq) AS TransMaxValueContd
FROM (
      SELECT
        PlaySeq,
        TransMaxValue,
        SUM(CASE WHEN TransMaxValue = 0 THEN 0 ELSE 1 END) OVER(ORDER BY PlaySeq) AS Grp
      FROM @Tab
) AS tbl
ORDER BY PlaySeq

答案 2 :(得分:0)

请尝试以下解决方案。

基于Windows函数ROW_NUMBER()和非等关系子句:

FROM @tbl AS t1 INNER JOIN 
            @tbl AS t2 ON t1.PlaySeq > t2.PlaySeq

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (PlaySeq INT, TransMaxValue INT);
INSERT INTO @tbl (PlaySeq, TransMaxValue) VALUES
(1, 250),
(2, 500),
(3, 0  ),
(4, 400),
(5, 0  ),
(6, 300),
(7, 500),
(8, 0  ),
(9, 0  );
-- DDL and sample data population, end

;WITH rs AS
(
    SELECT t1.*
        , t2.TransMaxValue AS prev_value
        , ROW_NUMBER() OVER (PARTITION BY t1.PlaySeq ORDER BY t2.PlaySeq DESC) AS seq
    FROM @tbl AS t1 INNER JOIN 
        @tbl AS t2 ON t1.PlaySeq > t2.PlaySeq
    WHERE t2.TransMaxValue > 0
)
SELECT PlaySeq, TransMaxValue, TransMaxValue AS TransMaxValueContd
FROM @tbl WHERE PlaySeq = 1
UNION ALL
SELECT PlaySeq, TransMaxValue, IIF(TransMaxValue > 0, TransMaxValue, prev_value) AS TransMaxValueContd
FROM rs
WHERE seq = 1
ORDER BY PlaySeq ASC;

输出

+---------+---------------+--------------------+
| PlaySeq | TransMaxValue | TransMaxValueContd |
+---------+---------------+--------------------+
|       1 |           250 |                250 |
|       2 |           500 |                500 |
|       3 |             0 |                500 |
|       4 |           400 |                400 |
|       5 |             0 |                400 |
|       6 |           300 |                300 |
|       7 |           500 |                500 |
|       8 |             0 |                500 |
|       9 |             0 |                500 |
+---------+---------------+--------------------+

答案 3 :(得分:0)

可能有更好的方法,但您可以尝试使用相关子查询:

SELECT q.PlaySeq, q.TransMaxValue
 , (CASE 
      WHEN q.TransMaxValue <> 0 THEN q.TransMaxValue 
      ELSE (SELECT d.TransMaxValue FROM myTable d WHERE d.PlaySeq = q.PlaySeqRef) 
    END) TransMaxValueContd
      FROM (
         SELECT PlaySeq
              , TransMaxValue
              , (SELECT MAX(PlaySeq) 
                    FROM myTable b 
                   WHERE b.PlaySeq < a.PlaySeq 
                     AND b.TransMaxValue <> 0) PlaySeqRef
             FROM myTable a) q;
相关问题