【问题标题】:SQL SELECT last entry without limitingSQL SELECT 最后一个条目没有限制
【发布时间】:2012-08-24 22:17:08
【问题描述】:

我有一个包含 3 个字段的表格:

id
note
created_at

在 SQL 语言中,尤其是 Postgres 中有没有一种方法可以选择最后一个 note 的值而无需 LIMIT 1?

普通查询:

select note from table order by created_at desc limit 1

我对避免限制的东西感兴趣,因为我需要它作为子查询。

【问题讨论】:

  • “我对避免限制的东西感兴趣,因为我需要它作为子查询。”这是避免使用有用功能的愚蠢理由。 真正的原因是什么?你的实际问题是什么?发布您的代码和您得到的错误。您有什么要求和顾虑?解释为什么 LIMIT 不能满足您的要求。
  • 这里和这个问题有关:stackoverflow.com/questions/12112990/…

标签: mysql sql postgresql limit


【解决方案1】:

带有EXISTS semi-join的简单版:

SELECT note FROM tbl t
WHERE  NOT EXISTS
    (SELECT 1 FROM tbl t1 WHERE t1.created_at > t.created_at);

“查找以后没有其他笔记创建的笔记。”

这与@Hogan 版本的弱点相同,即如果created_at 不是UNIQUE,它可以返回多行——就像@Ollie 已经指出的那样。与@Hogan 的查询不同(max() 仅针对简单类型定义),这一查询可以轻松改进:

比较行类型

SELECT note FROM tbl t
WHERE  NOT EXISTS
   (SELECT 1 FROM tbl t1
    WHERE  (t1.created_at, t1.id) > (t.created_at, t.id));

假设您想要最大的id 以防与created_at 并列,并且id 是主键,因此是唯一的。这适用于 PostgreSQL 和 MySQL。

SQL Fiddle.

窗口函数

在 PostgreSQL 中使用window function 可以实现相同的目的:

SELECT note
FROM  (
    SELECT note, row_number() OVER (ORDER BY created_at DESC, id DESC) AS rn
    FROM   tbl t 
    ) x
WHERE  rn = 1;

MySQL 缺乏对窗口函数的支持。你可以用这样的变量代替:

SELECT note
FROM  (
    SELECT note, @rownum := @rownum + 1 AS rn
    FROM   tbl t 
         ,(SELECT @rownum := 0) r
    ORDER  BY created_at DESC, id DESC
    ) x
WHERE  rn = 1;

(SELECT @rownum := 0) r 在没有明确的SET 命令的情况下使用 0 初始化变量。

SQL Fiddle.

【讨论】:

    【解决方案2】:

    如果您的 id 列是一个自动递增的主键字段,这很容易。这假设最新的笔记具有最高的 id。 (这可能不是真的;只有你自己知道!)

    select *
      from note
     where id = (select max(id) from note)
    

    在这里:http://sqlfiddle.com/#!2/7478a/1/0 用于 MySQL,http://sqlfiddle.com/#!1/6597d/1/0 用于 postgreSQL。相同的 SQL。

    如果您的 id 列未设置,因此最新注释具有最高 id,但仍然是主键(也就是说,每行中仍然具有唯一值),这有点困难。我们必须消除相同日期的歧义;我们将通过任意选择最高 id 来做到这一点。

    select *
      from note
      where id = (
                  select max(id)
                    from note where created_at = 
                       (select max(created_at) 
                          from note
                       )
                  )
    

    这是一个示例:http://sqlfiddle.com/#!2/1f802/4/0 用于 MySQL。 这是用于 postgreSQL 的(SQL 是一样的,耶!)http://sqlfiddle.com/#!1/bca8c/1/0

    另一种可能性:如果它们是同时创建的,也许您希望 两个 笔记一起显示在一行中。再说一次,只有你自己知道。

    select group_concat(note separator '; ') 
      from note 
     where created_at = (select max(created_at) from note)
    

    在 postgreSQL 9+ 中,它是

     select string_agg(note, '; ') 
       from note 
      where created_at = (select max(created_at) from note)
    

    如果您确实有可能出现重复的 created_at 时间和重复的 id 值,并且您不希望 group_concat 效果,那么很遗憾您被 LIMIT 卡住了。

    【讨论】:

    • 至于你的最后一句话:嗯,PostgreSQL 有窗口函数,MySQL 有变量替代。
    【解决方案3】:

    我不是 100% 使用 Postgres(实际上从未使用过它),但你可以通过类似的方式获得相同的效果 - 如果 created_at 是唯一的......(或任何唯一的列):

    SELECT note FROM table WHERE created_at = (
        SELECT MAX(created_at) FROM table
    )
    

    【讨论】:

    • 那不一样。不能保证只返回一行(除非created_at 上有唯一的约束)。
    • @MarkByers - 我会发誓我的回答是“如果日期是唯一的”。你没看第二行吗?
    【解决方案4】:

    我可能不知道如何在这个平台上回答,但我的建议是有效的

    SELECT * FROM table GROUP BY field ORDER BY max(field) DESC;
    

    可以不限制地获取字段的最后一个值,通常在JOINED查询中我们这样获取不限制输出的最后更新时间,例如不限制最后消息时间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-09
      • 1970-01-01
      • 1970-01-01
      • 2010-10-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多