【问题标题】:Get rowset based on distinct combination of columns根据不同的列组合获取行集
【发布时间】:2020-04-28 17:37:53
【问题描述】:

鉴于此数据集,每只股票都有年度价值快照。

+----+------+------+-------+-------+
| ID | Name | Year | Stock | Value |
+----+------+------+-------+-------+
|  1 | John | 2019 | ABC   |   123 |
|  1 | John | 2020 | ABC   |   123 |
|  1 | John | 2021 | ABC   |   123 |
|  1 | John | 2021 | XYZ   |   200 |
| 1  | John | 2022 | ABC   |   123 |
|  1 | John | 2022 | XYZ   |   200 |
|  1 | John | 2023 | ABC   |   630 |
|  1 | John | 2023 | XYZ   |   200 |
+----+------+------+-------+-------+

2019年,约翰只持有价值123的ABC

2020年,约翰也只持有ABC,价值123(未变)

2021年,John持有ABC,但也收购了XYZ,价值200

2022 年,John 持有 ABC 和 XYZ,这两个值都没有变化。

2023年,约翰持有ABC和XYZ,ABC的价值增加到630,XYZ的价值保持在200。

我想返回行以便

  • 每年,如果 John 的投资组合自去年以来没有任何变化,则不会返回任何行
  • 如果 John 的投资组合自去年以来发生任何变化,则会列出他目前持有的所有资产

例如,

+----+------+------+-------+-------+
| ID | Name | Year | Stock | Value |
+----+------+------+-------+-------+
|  1 | John | 2019 | ABC   |   123 |
|  1 | John | 2021 | ABC   |   123 |
|  1 | John | 2021 | XYZ   |   200 |
|  1 | John | 2023 | ABC   |   630 |
|  1 | John | 2023 | XYZ   |   200 |
+----+------+------+-------+-------+

我将如何做到这一点,无论是通过 PL/SQL 中的函数还是纯 SQL 中的函数?

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    如果每个用户的行数不多,那么listagg() 提供了一个方便的解决方案:

    select ny.*
    from (select name, year,
                 listagg(stock || ':' || value, ',') within group (order by stock) as stocks,
                 lag(listagg(stock || ':' || value, ',') within group (order by stock)) as prev_stocks,
                 lag(year) over (partition by name order by year) as prev_year
          from t
          group by name, year
         ) ny
    where prev_year is null or prev_year <> year - 1 or prev_stocks <> stocks;
    

    或者,您可以单独检查每一行并使用分析函数将信息投影到名称/年份中的所有行:

    select t.*
    from (select t.*,
                 sum(case when prev_nsv_year = year then 0 else 1 end) over (partition by name, year) as num_diff,
                 lag(cnt) over (partition by name order by year) as prev_cnt
          from (select t.*,
                       lag(year) over (partition by name, stock, value over order by year) as prev_nsv_year,
                       count(*) over (partition by name, year) as cnt
                from t
               ) t
         ) t
    where cnt <> prev_cnt or prev_cnt is null or
          num_diff > 0;
    

    【讨论】:

    • listagg 方法将每只股票一起返回到一个字符串中,有没有办法按照我上面展示的示例将每只股票作为单独的行?
    • @edkrs 。 . .答案中有两个疑问。第二个返回单独的行。
    猜你喜欢
    • 1970-01-01
    • 2018-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-31
    • 2021-07-08
    相关资源
    最近更新 更多