【问题标题】:T-SQL OVER/PARTITION BY query with condition带条件的 T-SQL OVER/PARTITION BY 查询
【发布时间】:2018-08-30 08:59:20
【问题描述】:

我正在为 SQL 查询而苦苦挣扎,虽然我查看了许多类似的答案,但没有一个非常适合我的情况。我有一个数据集如下:

Date1       Amount 1    Index   Date2               Type Supplier
31/03/2018  410000.00   17      16/04/2018 06:27    102  A
31/03/2018  410000.00   17      16/04/2018 06:31    102  B
31/03/2018  400000.00   2       16/04/2018 06:37    102  A
31/03/2018  400000.00   2       16/04/2018 06:38    102  B
30/06/2018  0           20      04/07/2018 08:23    202  A
30/06/2018  0           20      04/07/2018 08:23    202  B
30/06/2018  412000.00   20      06/07/2018 12:46    102  A
30/06/2018  412000.00   20      06/07/2018 12:47    102  B
30/06/2018  442000.00   100     16/07/2018 06:27    102  A
30/06/2018  442000.00   100     16/07/2018 06:31    102  B

对于有多个具有相同类型的行的每个 Date1,我只想要索引与最大 Date2 的索引匹配的行,所以我想要这个输出:

Date1       Amount 1    Index   Date2               Type Supplier
31/03/2018  400000.00   2       16/04/2018 06:37    102  A
31/03/2018  400000.00   2       16/04/2018 06:38    102  B
30/06/2018  0           20      04/07/2018 08:23    202  A
30/06/2018  0           20      04/07/2018 08:23    202  B
30/06/2018  442000.00   100     16/07/2018 06:27    102  A
30/06/2018  442000.00   100     16/07/2018 06:31    102  B

我觉得使用某种形式的条件 MAX() OVER (PARTITION BY) 应该是可能的,但对于我的一生,我无法弄清楚如何去做。

【问题讨论】:

  • 无法理解您的输出.. 对于日期 31/03/2018,您的数据中有多行具有不同的 INDEX 值.. 但您的输出并未显示每个索引值
  • 这正是重点 - 我想排除索引值与该 Date1 列的最大 Date2 的索引不匹配的行。我已经修改了 3 月份的数字以使其更清晰。
  • 你的数据只有一列INDEX .. DATE2的索引值是多少?
  • 你能说出为什么前两行被排除在外吗?只是一个例子来理解输出的逻辑
  • 对于日期 31/03 和类型 102,具有最高 date2 的行具有索引 2。因此,排除具有该日期和类型且索引不是 2 的任何行。对吗?

标签: sql sql-server window-functions


【解决方案1】:

LAST_VALUE (Transact-SQL) 解析函数与子查询一起使用。

以下工作示例适用于 Oracle(我更喜欢 Oracle,因为在 SQLServer 上转换日期总是有问题),但查询的思想是相同的,语法也相同:

演示:http://www.sqlfiddle.com/#!4/004ce7/19

SELECT * FROM (
   SELECT t.* ,
     last_value( "INDEX" ) OVER 
        ( partition by date1, "TYPE" order by date2
          ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) xx
   FROM table1 t
) x
WHERE xx = "INDEX"
ORDER BY date1;

|                DATE1 | AMOUNT1 | INDEX |                 DATE2 | TYPE | SUPPLIER |  XX |
|----------------------|---------|-------|-----------------------|------|----------|-----|
| 2018-03-31T00:00:00Z |  400000 |     2 | 2018-04-16 06:37:00.0 |  102 |        A |   2 |
| 2018-03-31T00:00:00Z |  400000 |     2 | 2018-04-16 06:38:00.0 |  102 |        B |   2 |
| 2018-06-30T00:00:00Z |  442000 |   100 | 2018-07-16 06:27:00.0 |  102 |        A | 100 |
| 2018-06-30T00:00:00Z |  442000 |   100 | 2018-07-16 06:31:00.0 |  102 |        B | 100 |
| 2018-06-30T00:00:00Z |       0 |    20 | 2018-07-04 08:23:00.0 |  202 |        B |  20 |
| 2018-06-30T00:00:00Z |       0 |    20 | 2018-07-04 08:23:00.0 |  202 |        A |  20 |

【讨论】:

  • 我喜欢这个简洁的特性,但不幸的是我在 SQL Server 2008 上并且 LAST_VALUE 还没有到达那里:(
【解决方案2】:

使用 row_number()

SELECT [Date1],[Amount 1],[Index],[Date2],[Type],[Supplier]
FROM (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY [Date1] ORDER BY [Date2] DESC) AS rn
    FROM tablename
) a
WHERE a.rn in( 1,2)

【讨论】:

    【解决方案3】:

    试试这个

    ;WITH CTE
    AS
    (
        SELECT
            *,
            MxDt =ROW_NUMBER() OVER(PARTITION BY Date1,[Type] ORDER BY Date2 DESC)
            FROM YourTableName
    )
    SELECT
        *
        FROM CTE C1
            WHERE EXISTS
            (
                SELECT
                    1
                    FROM CTE C2
                        WHERE [Index] = C1.[Index]
                            AND [Type]= C1.[Type]
                            AND C2.MxDt =1
            )
    

    【讨论】:

    • 虽然不像我希望的那样干净,但它确实对我有用,非常感谢。
    • 经过进一步调查,当系统中有多个 Date1 实例时,它会失败。 :(
    【解决方案4】:

    我想这就是你想要的。请注意使用ROW_NUMBER 而不是RANK - RANK 将产生多个值1,其中Date2 相同,ROW_NUMBER 将为rn 产生唯一的增量值:

    SELECT
        [Date1],
        [Amount 1],
        [Index],
        [Date2],
        [Type],
        [Supplier]
    FROM my_table
    INNER JOIN (
        SELECT
            [Index],
            [Type],
            ROW_NUMBER() OVER (PARTITION BY [Date1], [Type] ORDER BY [Date2] DESC) AS rn
        FROM my_table
    ) AS subquery
        ON subquery.rn = 1
        AND subquery.[Index] = my_table.[Index]
        AND subquery.[Type] = my_table.[Type]
    

    【讨论】:

    • 我可以看到你在这里做什么,但我无法让它在我的环境中工作 - 数据集并不像我在问题中显示的那么简单。
    • @DomG 道歉,我没有看到规定是设置(Date1Type)。我已经修好了,现在应该好了
    【解决方案5】:

    子查询对您的数据进行排序,以便控制索引的行对于每一组日期和类型始终为 row_no one。外部查询返回具有相同 date1、类型、索引组合的所有行,但忽略其他行

    Select *
    From Data D
        inner join SortedData S on S.Date1 = A.Date1 
              and S.Type = A.Type 
              and S.RowNo = 1 
              and D.Index = A.index
    
    (Select Date1, Type, Index, row_Number() over (Partition by Date1, Type ORDER BY Date2 DESC) as RowNo From Data) SortedData
    

    【讨论】:

      【解决方案6】:

      您可以使用相关子查询:

      select t.*
      from table t
      where Index = (select top (1) t1.Index
                     from table t1
                     where t1.Date1 = t.Date1 and t1.type = t.type
                     order by t1.date2 desc
                    );   
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-11-04
        • 2021-12-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-01
        • 2021-11-20
        相关资源
        最近更新 更多