根据 Knex 中的列仅选择不同的行

Selecting only distinct rows based on a column in Knex

我正在使用 Knex,一个非常好的 SQL 生成器。

我有一个名为 Foo 的 table,它有 3 列

+--------------+-----------------+
| id           | PK              |
+--------------+-----------------+
| idFoo        | FK (not unique) |
+--------------+-----------------+
| serialNumber | Number          |
+--------------+-----------------+

我想 select 所有 idFoo IN (1, 2, 3) 的行。

但是我想避免基于相同 idFoo 的重复记录。

由于该列不是唯一的,因此可能有许多行具有相同的 idFoo

可能的解决方案

我上面的查询当然 return 全部带有 idFoo IN (1, 2, 3),甚至重复。

db.select(
  "id",
  "idFoo",
  "age"
)
.from("foo")
.whereIn("idFoo", [1, 2, 3])

然而,这将 return 结果与重复的 idFoo 类似:

+----+-------+--------------+
| id | idFoo | serialNumber |
+----+-------+--------------+
| 1  | 2     | 56454        |
+----+-------+--------------+
| 2  | 3     | 75757        |
+----+-------+--------------+
| 3  | 3     | 00909        |
+----+-------+--------------+
| 4  | 1     | 64421        |
+----+-------+--------------+

我需要的是这个:

+----+-------+--------------+
| id | idFoo | serialNumber |
+----+-------+--------------+
| 1  | 2     | 56454        |
+----+-------+--------------+
| 3  | 3     | 00909        |
+----+-------+--------------+
| 4  | 1     | 64421        |
+----+-------+--------------+

我可以获取结果并使用 Javascript 过滤掉重复项。我特别想避免这种情况并在 Knex 中编写它。

问题是如何使用 Knex 代码执行此操作?

我知道它可以用普通的 SQL 来完成(也许使用 GROUP BY 的东西)但我特别想在 "pure" knex 中实现这个而不使用原始 SQL.

在正常情况下 sql 你这样做。

您执行 self join 并尝试查找具有相同 idFoo 但更大 id 的行,如果您没有找到它,那么您有 NULL。并且会知道你是更大的。

 SELECT t1.id, t1.idFoo, t1.serialNumber
 FROM foo as t1
 LEFT JOIN foo as t2
   ON t1.id < t2.id
  AND t1.idFoo = t2.idFoo  
 WHERE t2.idFoo IS NULL

所以在 knex.js

上检查 left join

编辑:

只需查看构建此文件的文档(未测试):

 knex.select('t1.*')
     .from('foo as t1')
     .leftJoin('foo as t2', function() {
        this.on('t1.id', '<', 't2.id')
            .andOn('t1.idFoo ', '=', 't2.idFoo')
        })
     .whereNull("t2.idFoo") 

Knex.js 原生支持 groupBy。你可以这样写:

knex('foo').whereIn('id',
  knex('foo').max('id').groupBy('idFoo')
)

改写为如下SQL:

SELECT * FROM foo
  WHERE id IN (
    SELECT max(id) FROM foo
      GROUP BY idFoo
  )

请注意,您需要使用子选择来确保您不会混合同一组中不同行的值。