【问题标题】:How to select k-th record per field in a single SQL query如何在单个 SQL 查询中为每个字段选择第 k 条记录
【发布时间】:2019-05-23 22:09:47
【问题描述】:

请帮我解决以下问题。我已经花了一周时间尝试将所有逻辑放入一个 SQL 查询中,但仍然没有得到优雅的结果。希望SQL高手给点提示,

我有一个包含 4 个字段的表:日期、过期月、过期年和值。主键在 3 个第一个字段上定义。因此,对于一个具体的日期,很少有不同的 expire_month、expire_year 值存在。我需要为每个日期从它们中选择一个值,显示在表格中。

例如,当我执行查询时:

SELECT date, expire_month, expire_year, value FROM futures 
WHERE date = ‘1989-12-01' ORDER BY expire_year, expire_month;

我得到一个按到期时间排序的同一日期的值列表(月份用字母编码):

1989-12-01  Z   1989    408.25
1989-12-01  H   1990    408.25
1989-12-01  K   1990    389
1989-12-01  N   1990    359.75
1989-12-01  U   1990    364.5
1989-12-01  Z   1990    375

该日期的正确单个值是从顶部开始的第 k 个记录。例如,of k 是 2,那么«正确的单个»记录将是:

1989-12-01  H   1990    408.25

如何为表格中的每个日期选择这些“正确的单一”值?

【问题讨论】:

标签: sql sqlite select


【解决方案1】:

您可以使用rank()

select t.date, t.expire_month, t.expire_year, t.value from (
  select *,
    rank() over(partition by date order by expire_year, expire_month) rn
  from futures 
) t
where t.rn = 2

子查询中的列rn,实际上是date分组的行的排名。
2 更改为您想要的等级。

【讨论】:

  • 非常感谢!这是解决我的问题的一种非常优雅和简单的方法。它适用于从 3.25 版开始的 SQLite,但是在最新版本的 SQLiteStudio 中不起作用...
  • 我不敢相信 SQLiteStudio 仍然落后那么远。这就是我使用 DB Browser for SQLite 的原因。
  • 感谢您的提示!我也要试试 DB 浏览器!
【解决方案2】:

虽然 forpas 的答案是更好的答案(虽然我认为我会在这里使用 row_number() 而不是 rank()),但窗口函数是最近添加到 Sqlite 的(在 3.25 中)。如果您卡在旧版本上并且无法升级,这里有一个替代方案:

SELECT date, expire_month, expire_year, value
FROM futures AS f
WHERE (date, expire_month, expire_year) =
      (SELECT f2.date, f2.expire_month, f2.expire_year
       FROM futures AS f2
       WHERE f.date = f2.date
       ORDER BY f2.expire_year, f2.expire_month
       LIMIT 1 OFFSET 1)
ORDER BY date;

OFFSET 的值比第 K 行小 1 - 因此第二行为 1,第三行为 2,依此类推。

不过,它为表中的每一行执行一个相关子查询,这并不理想。希望您的复合主键列按date, expire_year, expire_month 的顺序排列,这将有助于消除额外排序的需要。

【讨论】:

    【解决方案3】:

    您可以尝试以下查询。

    select * from 
    (
    SELECT rownum seq, date1, expire_month, expire_year, value FROM testtable
    WHERE date1 = to_date('1989-12-01','yyyy-mm-dd') 
    ORDER BY expire_year, expire_month
    )
    where seq=2
    

    【讨论】:

    • Sqlite 没有 to_date() 函数,并且 OP 的帖子中没有任何内容表明存在 rownum 列(或 date1 一个。错字?)
    • 我在 Oracle 中测试过。它工作得很好。 date1 只是为了避免与关键字冲突,我一般避免使用关键字作为变量名。
    • 这在 Oracle 中运行良好,我没想到至少会投反对票。
    猜你喜欢
    • 2012-12-10
    • 1970-01-01
    • 2020-06-21
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    • 1970-01-01
    • 2010-10-09
    • 1970-01-01
    相关资源
    最近更新 更多