根据 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
)
请注意,您需要使用子选择来确保您不会混合同一组中不同行的值。
我正在使用 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
)
请注意,您需要使用子选择来确保您不会混合同一组中不同行的值。