Knex 子查询对第二个表中的数据求和

Posted

技术标签:

【中文标题】Knex 子查询对第二个表中的数据求和【英文标题】:Knex subquery to sum data from 2nd table 【发布时间】:2019-12-31 02:06:03 【问题描述】:

我正在尝试使用 knex 编写一个查询来对每个问题的投票求和,但没有得到正确的总和。我可以用 SQL 编写子查询,但似乎无法将它们拼凑在一起。我是一名学生,不确定我是否对 Knex 做错了,或者我的基本逻辑是否错误。提前感谢您的帮助!

我的 knex 查询看起来像这样

return knex
  .from('question')
  .select(
    'question.id AS question_id',
    knex.raw(
      `count(DISTINCT vote) AS number_of_votes`, //this returns the number_of_votes for each question_id as expected
    ),
    knex.raw(
      `sum(vote.vote) AS sum_of_votes`, //something wrong here... E.g., question_id 1 has 3 down votes so the sum should be -3, however I am getting -9
    ),
  )
  .leftJoin('user', 'question.user_id', 'user.id')
  .leftJoin('vote', 'question.id', 'vote.question_id')
  .groupBy('question.id', 'user.id');

有 3 个表格看起来像:

用户

身份证 用户名

问题

身份证 标题 身体 user_id(FK 引用 user.id)

投票

question_id(FK 引用 question.id) user_id(FK 引用 user.id) 投票(-1 或 1) 主键(question_id、user_id)

我确实设法将查询编写为独立的 SQL 查询,并验证它是否按预期工作。这就是我在上面的 knex 查询中想要完成的:

SELECT question.id, sum(vote.vote) AS sum_of_votes FROM question LEFT JOIN vote ON question.id = vote.question_id GROUP BY question.id;

【问题讨论】:

您的工作查询未加入users,这可能会对结果产生影响。尝试从 knex 中删除用户加入,看看结果是否正确 附加输入,您的查询可能会在没有投票的情况下汇总问题,因为您正在对问题进行投票,有些问题尚未投票,结果将是null,并且可能与Sum混淆,尝试将 sum 语句更改为Sum(IsNull(vote.vote, 0)) 嗯,这些似乎都不起作用。我认为正在发生的事情是投票总和乘以问题被投票的次数...回到问题 1 的示例有 3 票反对票(预计 -3 为 vote_sum)。它实际上被报告了 3 倍(对问题的每个投票实例一次),然后求和。但我不确定如何让它只报告每个问题的总和 1x。 【参考方案1】:

所以,总的来说,您的 SQL 查询是正确的(在修正了几个拼写错误之后),尽管正如 @felixmosh 指出的那样,其中没有用户信息:可能很难弄清楚谁投票给了什么!但也许你不需要它来达到你的目的。

您发布的解决方案可以解决问题,但可能不是该作业最有效的查询,因为它涉及一个子查询和多个连接。这是它生成的 SQL:

SELECT "question"."id" AS "question_id",
  count(DISTINCT vote) AS number_of_votes,
  (
    SELECT sum(vote) FROM vote
      WHERE question_id = question.id
      GROUP BY question_id
  ) AS sum_of_votes
  FROM "question"
  LEFT JOIN "user" ON "question"."user_id" = "user"."id"
  LEFT JOIN "vote" ON "question"."id" = "vote"."question_id"
  GROUP BY "question"."id", "user"."id";

我们可以采取更简单的方法来获取相同的信息。这个怎么样?

SELECT question_id,
  count(vote) AS number_of_votes,
  sum(vote) AS sum_of_votes
  FROM vote
  GROUP BY question_id;

这将获取您正在寻找的所有信息,而无需连接任何表或使用子查询。它还避免了DISTINCT,这可能导致错误地计算票数。生成此类查询的 Knex 如下所示:

knex("vote")
  .select("question_id")
  .count("vote AS number_of_votes")
  .sum("vote AS sum_of_votes")
  .groupBy("question_id")

只有在您想从这些表中查找更多信息(例如用户名或问题标题)时,您才真正需要在此处加入表。

【讨论】:

【参考方案2】:

经过几个小时的尝试,我终于明白了。这是解决方案:

return knex
  .from('question')
  .select(
    'question.id AS question_id',
    knex.raw(
      `count(DISTINCT vote) AS number_of_votes`,
    ),
    knex.raw(
    `SELECT sum(vote) from vote WHERE question_id = question.id GROUP BY question_id) AS sum_of_votes`
  )
  .leftJoin('user', 'question.user_id', 'user.id')
  .leftJoin('vote', 'question.id', 'vote.question_id')
  .groupBy('question.id', 'user.id');

【讨论】:

以上是关于Knex 子查询对第二个表中的数据求和的主要内容,如果未能解决你的问题,请参考以下文章

如何加入/子查询第二个表

kusto 如何编写子查询

如何使用子查询的多行返回值插入表中?

bigquery:依靠子查询的联合

将第二个表中的第二个(条件)结果添加到 SQL 查询

选择数组、子查询和多行结果