如何检索"最后"多列的非零值?

时间:2017-10-11 13:42:56

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

考虑一个有11列的有序表:
timespan, val1, val2, val3, val4, val5, val6, val7, val8, val9 and val10

假设一组记录如:

timespan     val1  val2  val3  val4  val5  val6  val7  val8  val9  val10
10/09/2011      0     0    60    80    40     0     0    40    80      0
10/10/2011      0    10    90    30    70    50    50    70    30     90
10/11/2011     10     0    20     0     0    60    60     0     0     20

我需要一个SQL查询(对于SQL Server 2012),它返回所有列的最后(及时)非零值,val1,val2,...,即

val1  val2  val3  val4  val5  val6  val7  val8  val9  val10
  10    10    20    30    70    60    60    70    30     20

类似的问题可以在Subquery: how to retrieve the last non-zero value from a column?找到,但它只适用于一列,并且包含更多列的概括(如本例所示)似乎不实用。

3 个答案:

答案 0 :(得分:1)

您可以使用first_value()

select distinct first_value(val1) over (order by sign(val1) desc, timespan desc) as val1,
       first_value(val2) over (order by sign(val2) desc, timespan desc) as val2,
       . . .
from t;

通常,我反对使用select distinct替代聚合查询。不幸的是,SQL Server支持first_value()作为窗口函数,但不提供聚合的等价物。

注意:sign()函数用于将零值放在最后。如果您可以使用负值,请使用abs(sign())

答案 1 :(得分:1)

另一种选择是快速拆卸,后跟枢轴

示例

Select *
 From  (
           Select top 1 with ties item,value
            From  YourTable
            UnPivot ( Value for Item in (val1,val2,val3,val4,val5,val6,val7,val8,val9,val10) ) u
            Where value<>0
            Order by Row_Number() over (Partition By item Order by timespan desc)
       ) src
 Pivot (max(value) For item in (val1,val2,val3,val4,val5,val6,val7,val8,val9,val10) ) p

<强>返回

val1    val2    val3    val4    val5    val6    val7    val8    val9    val10
10      10      20      30      70      60      60      70      30      20

答案 2 :(得分:0)

您可以使用以下内容。 1.逻辑是首先取消值,然后删除0个条目,然后将最后一个非零值计算为row_num = 1.

  1. 然后再次转动以获得结果。
  2. 查询在

    下面
    create table t
    (timespan date,val1 int,val2 int,val3 int,val4 int,val5 int,val6 int,val7 int,val8 int,val9 int,val10 int);
    insert into t values
    ('10/09/2011', 0, 0,60,80,40, 0, 0,40,80, 0)
    ,('10/10/2011', 0,10,90,30,70,50,50,70,30,90)
    ,('10/11/2011',10, 0,20, 0, 0,60,60, 0, 0,20);
    
    select * 
        from
    (
        select 
            value, Columns 
        from
        (
            select 
                timespan,
                value, 
                Columns, 
                row_number() over(partition by Columns order by timespan desc) r
            from
            (select * from t)s
            unpivot
            ( 
                value for Columns in 
                    ([val1],[val2],[val3],[val4],[val5],[val6],[val7],[val8],[val9],[val10])
            )up
            where value<>0
        ) t 
        where r=1
     )s
    pivot
    (
        max(value) for Columns in 
            ([val1],[val2],[val3],[val4],[val5],[val6],[val7],[val8],[val9],[val10])
    )p
    

    See working demo