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

时间:2016-12-01 20:31:28

标签: sql knex.js

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

我有一个名为Foo的表,其中有3列

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

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

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

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

可能的解决方案

我上面的查询当然会以idFoo IN (1, 2, 3)返回所有内容,甚至是重复内容。

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

然而,这将返回重复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)来完成它,但我特别想在不使用原始SQL的情况下在“纯”knex中实现这一点。

2 个答案:

答案 0 :(得分:1)

在普通的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") 

答案 1 :(得分:1)

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
  )

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