【问题标题】:Get last record of a table in Postgres在 Postgres 中获取表的最后一条记录
【发布时间】:2011-06-07 15:44:34
【问题描述】:

我正在使用 Postgres,无法获取表的最后一条记录:

 my_query = client.query("SELECT timestamp,value,card from my_table");

如果知道时间戳是记录的唯一标识符,我该怎么做?

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    如果在“最后一条记录”下你的意思是具有最新时间戳值的记录,那么试试这个:

    my_query = client.query("
      SELECT TIMESTAMP,
        value,
        card
      FROM my_table
      ORDER BY TIMESTAMP DESC
      LIMIT 1
    ");
    

    【讨论】:

    • 如果您没有描述插入时间的时间戳列怎么办?
    • @WebWanderer SELECT id,value,card FROM my_table ORDER BY id DESC LIMIT 1;
    • 关键是按 desc 使用 order 并在此之后限制 1....就像上面的示例查询中所示
    • 如果两行具有相同的时间戳,这会返回最后插入的行吗?
    • @user2233706,不一定。如果时间戳不明显,那么还有其他选项。例如,如果有一个从序列中填充的主键列,那么您可以选择具有最新 ID 的记录,CURRVAL(<sequence name>)
    【解决方案2】:

    你可以使用

    SELECT timestamp, value, card 
    FROM my_table 
    ORDER BY timestamp DESC 
    LIMIT 1
    

    假设您还想按timestamp 排序?

    【讨论】:

      【解决方案3】:

      简单方法:ORDER BY 与 LIMIT 结合使用

      SELECT timestamp, value, card
      FROM my_table
      ORDER BY timestamp DESC
      LIMIT 1;
      

      但是,LIMIT 不是标准的,正如Wikipedia 所述,SQL 标准的核心功能并未明确定义 Null 的默认排序顺序。。最后,当多条记录共享最大时间戳时,只返回一行。

      关系方式:

      执行此操作的典型方法是检查没有任何行的时间戳高于我们检索到的任何行。

      SELECT timestamp, value, card
      FROM my_table t1
      WHERE NOT EXISTS (
        SELECT *
        FROM my_table t2
        WHERE t2.timestamp > t1.timestamp
      );
      

      这是我最喜欢的解决方案,也是我倾向于使用的解决方案。缺点是当我们看到这个查询时,我们的意图并不是很清楚。

      指导方式:MAX

      为了避免这种情况,可以在子查询中使用 MAX 而不是相关性。

      SELECT timestamp, value, card
      FROM my_table
      WHERE timestamp = (
        SELECT MAX(timestamp)
        FROM my_table
      );
      

      但是如果没有索引,则需要对数据进行两次传递,而前一个查询只需一次扫描即可找到解决方案。也就是说,除非必要,否则我们在设计查询时不应考虑性能,因为我们可以预期优化器会随着时间的推移而改进。然而,这种特殊的查询非常常用。

      炫耀方式:窗口化函数

      我不建议这样做,但也许你可以给你的老板或其他人留下好印象;-)

      SELECT DISTINCT
        first_value(timestamp) OVER w,
        first_value(value) OVER w,
        first_value(card) OVER w
      FROM my_table
      WINDOW w AS (ORDER BY timestamp DESC);
      

      实际上,这表明一个简单的查询可以用多种方式表达(我可以想到其他几种方式),并且应该根据几个标准来选择一种或另一种形式,例如如:

      • 可移植性(关系/指导方式)
      • 效率(关系方式)
      • 表现力(简单/指导方式)

      【讨论】:

        【解决方案4】:

        如果您接受小费,请在此表中创建一个 id,如 serial。该字段的默认值为:

        nextval('table_name_field_seq'::regclass).
        

        因此,您使用查询来调用最后一个寄存器。使用您的示例:

        pg_query($connection, "SELECT currval('table_name_field_seq') AS id;
        

        我希望这个提示对你有所帮助。

        【讨论】:

        • 对不起,我的英语不好。
        • 如果最后一行最终被删除,这仍然会返回其 id...不是安全提示 :)
        • 返回 nextval 在当前会话中为这个序列最近获得的值。 所以这不仅会在nextval 没有返回的情况下返回错误'未在当前会话中调用,但您也不会看到其他会话中所做的更改。
        【解决方案5】:

        假设您将“id”作为主键,则可以使用此查询最后插入的记录:

        SELECT timestamp,value,card FROM my_table WHERE id=(select max(id) from my_table)
        

        假设插入的每个新行都将使用表 id 的最大整数值。

        【讨论】:

          【解决方案6】:

          如果您的表没有整数自增等Id,也没有时间戳,您仍然可以通过以下查询获取表的最后一行。

          select * from <tablename> offset ((select count(*) from <tablename>)-1)
          

          例如,这可以让您搜索更新的平面文件,查找/确认先前版本的结束位置,并将剩余的行复制到您的表格中。

          【讨论】:

            【解决方案7】:

            使用下面的

            SELECT timestamp, value, card 
            FROM my_table 
            ORDER BY timestamp DESC 
            LIMIT 1
            

            【讨论】:

              【解决方案8】:

              要获取最后一行,

              按排序顺序获取最后一行:如果表中有指定时间/主键的列,

              1. 使用LIMIT 子句

              SELECT * FROM USERS ORDER BY CREATED_TIME DESC LIMIT 1;

              1. 使用FETCH 子句-Reference

              SELECT * FROM USERS ORDER BY CREATED_TIME FETCH FIRST ROW ONLY;

              获取行插入顺序中的最后一行:如果表中没有指定时间/任何唯一标识符的列

              1. 使用CTID系统列,其中ctid表示表中行的物理位置-Reference

                SELECT * FROM USERS WHERE CTID = (SELECT MAX(CTID) FROM USERS);

              考虑下表,

              userid |username |    createdtime |
                   1 |       A |  1535012279455 |
                   2 |       B |  1535042279423 | //as per created time, this is the last row
                   3 |       C |  1535012279443 |
                   4 |       D |  1535012212311 |
                   5 |       E |  1535012254634 | //as per insertion order, this is the last row
              

              查询 1 和 2 返回,

              userid |username |    createdtime |
                   2 |       B |  1535042279423 |
              

              当 3 返回时,

              userid |username |    createdtime |
                   5 |       E |  1535012254634 |
              

              注意:更新旧行时,它会删除旧行并更新数据并作为新行插入表中。因此,使用以下查询将返回最迟对其进行数据修改的元组。

              现在更新一行,使用

              UPDATE USERS SET USERNAME = 'Z' WHERE USERID='3'

              表格变成了,

              userid |username |    createdtime |
                   1 |       A |  1535012279455 |
                   2 |       B |  1535042279423 |
                   4 |       D |  1535012212311 |
                   5 |       E |  1535012254634 |
                   3 |       Z |  1535012279443 |
              

              现在查询 3 返回了,

              userid |username |    createdtime |
                   3 |       Z |  1535012279443 |
              

              【讨论】:

                【解决方案9】:

                这些都是很好的答案,但是如果您想要一个聚合函数来执行此操作以获取由任意查询生成的结果集中的最后一行,there's a standard way to do this(取自 Postgres wiki,但应该可以在任何符合合理要求的情况下工作十年或更久以前的 SQL 标准):

                -- Create a function that always returns the last non-NULL item
                CREATE OR REPLACE FUNCTION public.last_agg ( anyelement, anyelement )
                RETURNS anyelement LANGUAGE SQL IMMUTABLE STRICT AS $$
                        SELECT $2;
                $$;
                
                -- And then wrap an aggregate around it
                CREATE AGGREGATE public.LAST (
                        sfunc    = public.last_agg,
                        basetype = anyelement,
                        stype    = anyelement
                );
                

                如果您有合理的排序,通常最好使用select ... limit 1,但如果您需要在聚合中执行此操作并且希望避免子查询,这很有用。

                另请参阅this question,了解这是自然答案的情况。

                【讨论】:

                  【解决方案10】:

                  列名在降序中起重要作用:

                  select <COLUMN_NAME1, COLUMN_NAME2> from >TABLENAME> ORDER BY <COLUMN_NAME THAT MENTIONS TIME> DESC LIMIT 1;
                  

                  例如:下面提到的表(user_details)由列名“created_at”组成,该列具有该表的时间戳。

                  SELECT userid, username FROM user_details ORDER BY created_at DESC LIMIT 1;
                  

                  【讨论】:

                    【解决方案11】:

                    在 Oracle SQL 中,

                    select * from (select row_number() over (order by rowid desc) rn, emp.* from emp) where rn=1;
                    

                    【讨论】:

                    • 请在您的回答中添加解释
                    【解决方案12】:

                    select * from table_name LIMIT 1;

                    【讨论】:

                    • 这只返回一行。不是最后一条记录。
                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2019-12-28
                    • 2021-06-25
                    • 1970-01-01
                    • 2015-01-29
                    • 1970-01-01
                    • 2011-08-18
                    • 2012-05-10
                    相关资源
                    最近更新 更多