如何使用 Sequelize.JS 选择具有 2 个唯一列的所有行?

Posted

技术标签:

【中文标题】如何使用 Sequelize.JS 选择具有 2 个唯一列的所有行?【英文标题】:How to select all rows with 2 unique columns with Sequelize.JS? 【发布时间】:2022-01-13 13:25:36 【问题描述】:

我有一个名为 grade 的表,有 4 列:student_idsubject_idgradedate

student_id subject_id grade date
Jenny math 90 2021-12-08
Susan math 60 2021-12-08
Jenny math 80 2021-12-07
Susan math 50 2021-12-07
Jenny science 80 2021-12-08
Susan science 90 2021-12-08
Jenny science 76 2021-12-06
Susan science 85 2021-12-06

我想选择所有行,其中只有每个学生的每个科目的最后一个年级。基本上,我想选择所有具有唯一student_idsubject_id 的行,如下所示:

student_id subject_id grade date
Jenny math 90 2021-12-08
Susan math 60 2021-12-08
Jenny science 80 2021-12-08
Susan science 90 2021-12-08

这是我尝试过的:

await Grade.findAll(
    attributes: ['student_id', 'subject_id', 'grade', 'date'],
    raw: true,
    group: ['student_id', 'subject_id']
)

但是,我收到以下错误:

SequelizeDatabaseError: column "grade.grade" must appear in the GROUP BY clause or be used in an aggregate function

【问题讨论】:

我不知道如何在 Sequelize.JS 中编写,但在 postgres 中,您需要在 (student_id 和 subject_id ) 上按日期 DESC 顺序使用窗口函数和 【参考方案1】:

你很接近。您按student_idsubject_id 分组,只需要MAX('date')

await Grade.findAll(
    attributes: ['student_id', 'subject_id', 'grade', [Sequelize.fn('max', Sequelize.col('date')), 'date']],
    raw: true,
    group: ['student_id', 'subject_id']
)

属性中的数组可以执行给定名称[function, alias]的函数和别名。

例如:

[Sequelize.fn('max', Sequelize.col('date')), 'new_name']]

属性中的这种语法将 SQL 创建为

MAX(`date`) as `new_name`

================================================ =========

更新:

上述查询在 Postgres 中不起作用。

参考:https://dba.stackexchange.com/a/194352

要在 Postgres 中实现相同的查询,另一种解决方案是使用 DISTINCT ON

await Grade.findAll(
    attributes: [Sequelize.literal('DISTINCT ON ("student_id", "subject_id") *'),
    'id', 'student_id', 'subject_id', 'date', 'grade'],
    order: ['student_id', 'subject_id', ['date', 'DESC']]
)

更多DISTINCT ON查询,请查看https://zaiste.net/posts/postgresql-distinct-on/

本文还涉及到@sia 提到的窗口函数的使用。

DISTINCT ONROW_NUMBER 的一些有趣的基准测试 https://***.com/a/34715134/2956135

【讨论】:

谢谢@Emma!我尝试将id 添加到属性中并得到以下错误:SequelizeDatabaseError: column "grade.id" must appear in the GROUP BY clause or be used in an aggregate function。有什么想法吗? 您可以在原始问题中添加您当前的findAll 函数吗?请保留原代码。 您的回答无效,我收到以下错误:SequelizeDatabaseError: column "grade.grade" must appear in the GROUP BY clause or be used in an aggregate function。它仅在我删除 grade 属性时才有效。 我的错。我在sqlite 上进行测试,但在 postgres 中不允许使用此 SQL。我会更新的。 感谢@Emma 非常有帮助的回答!

以上是关于如何使用 Sequelize.JS 选择具有 2 个唯一列的所有行?的主要内容,如果未能解决你的问题,请参考以下文章

Sequelize.js 插入具有一对多关系的模型

Sequelize JS 自定义查询与子选择

如何在 Sequelize.js 中使用数据库连接池

如何使用 sequelize.js 从关联模型中加载属性

Node.js / Sequelize.js / Express.js - 如何插入多对多关联? (同步/异步?)

如何使用 Sequelize.js ORM 正确迁移 sqlite3 数据库?