Knex 子查询对来自第二个 table 的数据求和

Knex subquery to sum data from 2nd table

我正在尝试使用 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 个表格如下所示:

用户

问题

投票

我设法将查询编写为 stand-alone 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;

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

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');

所以,大体上你的 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")

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