You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Drizzle ORM+Next.js+PostgreSQL,无时间/自增列如何按最新数据排序并取指定条数?

解决思路与方案

首先得明确:UUID本身分版本,如果是UUID v1,它内置了时间戳信息,能直接用来排序;如果是UUID v4(随机生成),那只能通过补列或依赖PostgreSQL系统列来应急。


方案1:利用UUID v1的时间戳排序(如果你的UUID是v1)

UUID v1的前16个字符对应时间戳的十六进制值,可以通过PostgreSQL的字符串处理和类型转换提取出来,在Drizzle里直接用sql()函数生成排序逻辑:

import { sql } from 'drizzle-orm';
import { articles } from './schema';

const latestArticles = await db
  .select()
  .from(articles)
  .orderBy(sql`(substring(id from 1 for 8) || substring(id from 9 for 4))::bit(64)::bigint DESC`)
  .limit(10);

原理是把UUID的时间部分拼接后转成大整数,再倒序排序,这样就能拿到最新插入的10条数据,不用全表查询。


方案2:添加created_at列(推荐的长期方案)

如果你的UUID是v4(随机),或者不想依赖UUID的版本特性,最可靠的方式是给表加一个created_at列,同时补全历史数据的时间(如果能接受用当前时间或者近似值):

1. 用Drizzle修改表结构

在你的schema里添加字段:

import { timestamp } from 'drizzle-orm/pg-core';

export const articles = pgTable('articles', {
  // 其他字段...
  createdAt: timestamp('created_at').defaultNow().notNull(),
});

然后运行Drizzle的迁移命令更新表。

2. 补全历史数据的时间

如果需要给已有的8000+条数据补时间,可以用PostgreSQL的系统列ctid作为近似插入顺序(注意:ctid是物理行位置,有删除/更新操作会不准,仅作为临时补数据的参考):

UPDATE articles
SET created_at = NOW() - (SELECT MAX(ctid) - ctid FROM articles) * INTERVAL '1 second'
WHERE created_at IS NULL;

之后就可以正常用Drizzle的orderBy排序:

const latestArticles = await db
  .select()
  .from(articles)
  .orderBy(articles.createdAt, 'desc')
  .limit(10);

方案3:用PostgreSQL系统列应急(不推荐长期用)

如果暂时不能改表结构,且UUID是v4,可以尝试用ctid物理行位置排序(仅适用于没有频繁删除/更新的表,因为行移动会改变ctid):

import { sql } from 'drizzle-orm';
import { articles } from './schema';

const latestArticles = await db
  .select()
  .from(articles)
  .orderBy(sql`ctid DESC`)
  .limit(10);

这个方案是权宜之计,因为ctid不代表逻辑上的插入顺序,一旦有行被删除或更新,新插入的行可能会占用旧位置,导致排序混乱。


内容的提问来源于stack exchange,提问作者AmirHossein_Khakshouri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 15:56:06