【问题标题】:Repetitive entries in SQL JOIN querySQL JOIN 查询中的重复条目
【发布时间】:2016-09-06 05:03:05
【问题描述】:

我有三个表 postscmetsusers。 posts 表包括两种类型的帖子,questionanswer。对问题和答案进行评论。我的目的是得到一个带有 cmets 的问题,上面有答案,然后有 cmets 在那个答案上。我还需要用户表中的用户名作为我获取的每个问题、答案和评论的作者。我正在使用 Postgres 9.5,并使用 json_agg() 函数。

虽然我需要的示例输出应该类似于下面的第一个,但我得到了重复的条目。

我在这里缺少什么?可能是正确的 group by 子句。或者用他们的 cmets 收集答案的子查询不是这样做的方法。当我从 cmets 表上的帖子中注释掉左连接时,我在没有 cmets 问题的情况下得到了想要的结果。此外,当我取消包含子查询的左连接时,我得到了我所期望的非重复结果,这又不是我想要的完整数据集。这些是我迄今为止收集的用于解决我的问题的东西。

我需要什么:

[
  {
    "post_id": "10",
    "created_at": "2016-05-10T00:16:54.469Z",
    "post_type": "question",
    "post_title": "qwerty",
    "post_text": "asdasd asda sdasd",
    "post_author_id": 1,
    "author": "isikfsc",
    "parent_post_id": null,
    "is_accepted": null,
    "acceptor_id": null,
    "answers": [
      {
        "post_id": 17,
        "created_at": "2016-05-10T04:58:56.350229",
        "post_type": "answer",
        "post_title": null,
        "post_text": "222asda dasdad asdada",
        "post_author_id": 1,
        "author": "isikfsc",
        "parent_post_id": 10,
        "is_accepted": null,
        "acceptor_id": null,
        "comments": [
          {
            "id": 5,
            "created_at": "2016-05-10T10:56:30.220128",
            "text": "qweqwe",
            "author_id": 1,
            "author": "isikfsc",
            "parent_post_id": 17
          },
          {
            "id": 8,
            "created_at": "2016-05-10T11:00:00.182991",
            "text": "sasasd",
            "author_id": 1,
            "author": "isikfsc",
            "parent_post_id": 17
          }
        ]
      },
      {
        "post_id": 14,
        "created_at": "2016-05-10T04:19:19.005556",
        "post_type": "answer",
        "post_title": null,
        "post_text": "asdasdasdasd",
        "post_author_id": 1,
        "author": "isikfsc",
        "parent_post_id": 10,
        "is_accepted": null,
        "acceptor_id": null,
        "comments": [
          {
            "id": 2,
            "created_at": "2016-05-10T05:25:34.671008",
            "text": "qeqweqwe",
            "author_id": 1,
            "author": "isikfsc",
            "parent_post_id": 14
          }
        ]
      }
    ],
    "comments": [
        {
          "id": 1,
          "created_at": "2016-05-10T10:56:30.220128",
          "text": "qweqwe",
          "author_id": 1,
          "author": "isikfsc",
          "parent_post_id": 10
        },
        {
          "id": 4,
          "created_at": "2016-05-10T11:00:00.182991",
          "text": "sasasd",
          "author_id": 1,
          "author": "isikfsc",
          "parent_post_id": 10
        }
    ]
  }
]

我的查询是:

SELECT
    q.*,
    json_agg(ac.*) AS answers,
    json_agg(c.*) AS comments --comments on posts of post_id questions
FROM posts q

LEFT JOIN 
    (
        SELECT
            a.*,
            json_agg(c.*) AS comments -- comments on posts of post_id answers
        FROM posts a
        LEFT JOIN comments c
        ON a.post_id = c.parent_post_id

        GROUP BY a.post_id
    ) ac
ON q.post_id = ac.parent_post_id

LEFT JOIN comments c
ON q.post_id = c.parent_post_id

WHERE q.post_id = 10
GROUP BY q.post_id

我得到了什么:

[
  {
    "post_id": "10",
    "created_at": "2016-05-10T00:16:54.469Z",
    "post_type": "question",
    "post_title": "qwerty",
    "post_text": "asdasd asda sdasd",
    "post_author_id": 1,
    "parent_post_id": null,
    "is_accepted": null,
    "acceptor_id": null,
    "answers": [
      {
        "post_id": 17,
        "created_at": "2016-05-10T04:58:56.350229",
        "post_type": "answer",
        "post_title": null,
        "post_text": "222asda dasdad asdada",
        "post_author_id": 1,
        "parent_post_id": 10,
        "is_accepted": null,
        "acceptor_id": null,
        "comments": [
          {
            "id": 5,
            "created_at": "2016-05-10T10:56:30.220128",
            "text": "qweqwe",
            "author_id": 1,
            "parent_post_id": 17
          },
          {
            "id": 8,
            "created_at": "2016-05-10T11:00:00.182991",
            "text": "sasasd",
            "author_id": 1,
            "parent_post_id": 17
          }
        ]
      },
      {
        "post_id": 17,
        "created_at": "2016-05-10T04:58:56.350229",
        "post_type": "answer",
        "post_title": null,
        "post_text": "222asda dasdad asdada",
        "post_author_id": 1,
        "parent_post_id": 10,
        "is_accepted": null,
        "acceptor_id": null,
        "comments": [
          {
            "id": 5,
            "created_at": "2016-05-10T10:56:30.220128",
            "text": "qweqwe",
            "author_id": 1,
            "parent_post_id": 17
          },
          {
            "id": 8,
            "created_at": "2016-05-10T11:00:00.182991",
            "text": "sasasd",
            "author_id": 1,
            "parent_post_id": 17
          }
        ]
      },
      {
        "post_id": 17,
        "created_at": "2016-05-10T04:58:56.350229",
        "post_type": "answer",
        "post_title": null,
        "post_text": "222asda dasdad asdada",
        "post_author_id": 1,
        "parent_post_id": 10,
        "is_accepted": null,
        "acceptor_id": null,
        "comments": [
          {
            "id": 5,
            "created_at": "2016-05-10T10:56:30.220128",
            "text": "qweqwe",
            "author_id": 1,
            "parent_post_id": 17
          },
          {
            "id": 8,
            "created_at": "2016-05-10T11:00:00.182991",
            "text": "sasasd",
            "author_id": 1,
            "parent_post_id": 17
          }
        ]
      },
      {
        "post_id": 17,
        "created_at": "2016-05-10T04:58:56.350229",
        "post_type": "answer",
        "post_title": null,
        "post_text": "222asda dasdad asdada",
        "post_author_id": 1,
        "parent_post_id": 10,
        "is_accepted": null,
        "acceptor_id": null,
        "comments": [
          {
            "id": 5,
            "created_at": "2016-05-10T10:56:30.220128",
            "text": "qweqwe",
            "author_id": 1,
            "parent_post_id": 17
          },
          {
            "id": 8,
            "created_at": "2016-05-10T11:00:00.182991",
            "text": "sasasd",
            "author_id": 1,
            "parent_post_id": 17
          }
        ]
      },
      {
        "post_id": 14,
        "created_at": "2016-05-10T04:19:19.005556",
        "post_type": "answer",
        "post_title": null,
        "post_text": "asdasdasdasd",
        "post_author_id": 1,
        "parent_post_id": 10,
        "is_accepted": null,
        "acceptor_id": null,
        "comments": [
          {
            "id": 2,
            "created_at": "2016-05-10T05:25:34.671008",
            "text": "qeqweqwe",
            "author_id": 1,
            "parent_post_id": 14
          }
        ]
      },
      {
        "post_id": 14,
        "created_at": "2016-05-10T04:19:19.005556",
        "post_type": "answer",
        "post_title": null,
        "post_text": "asdasdasdasd",
        "post_author_id": 1,
        "parent_post_id": 10,
        "is_accepted": null,
        "acceptor_id": null,
        "comments": [
          {
            "id": 2,
            "created_at": "2016-05-10T05:25:34.671008",
            "text": "qeqweqwe",
            "author_id": 1,
            "parent_post_id": 14
          }
        ]
      },
      {
        "post_id": 14,
        "created_at": "2016-05-10T04:19:19.005556",
        "post_type": "answer",
        "post_title": null,
        "post_text": "asdasdasdasd",
        "post_author_id": 1,
        "parent_post_id": 10,
        "is_accepted": null,
        "acceptor_id": null,
        "comments": [
          {
            "id": 2,
            "created_at": "2016-05-10T05:25:34.671008",
            "text": "qeqweqwe",
            "author_id": 1,
            "parent_post_id": 14
          }
        ]
      },
      {
        "post_id": 14,
        "created_at": "2016-05-10T04:19:19.005556",
        "post_type": "answer",
        "post_title": null,
        "post_text": "asdasdasdasd",
        "post_author_id": 1,
        "parent_post_id": 10,
        "is_accepted": null,
        "acceptor_id": null,
        "comments": [
          {
            "id": 2,
            "created_at": "2016-05-10T05:25:34.671008",
            "text": "qeqweqwe",
            "author_id": 1,
            "parent_post_id": 14
          }
        ]
      }
    ],
    "comments": [
      {
        "id": 1,
        "created_at": "2016-05-10T05:25:28.200327",
        "text": "asadasdad",
        "author_id": 1,
        "parent_post_id": 10
      },
      {
        "id": 4,
        "created_at": "2016-05-10T10:25:23.381177",
        "text": "werwer",
        "author_id": 1,
        "parent_post_id": 10
      },
      {
        "id": 1,
        "created_at": "2016-05-10T05:25:28.200327",
        "text": "asadasdad",
        "author_id": 1,
        "parent_post_id": 10
      },
      {
        "id": 4,
        "created_at": "2016-05-10T10:25:23.381177",
        "text": "werwer",
        "author_id": 1,
        "parent_post_id": 10
      },
      {
        "id": 1,
        "created_at": "2016-05-10T05:25:28.200327",
        "text": "asadasdad",
        "author_id": 1,
        "parent_post_id": 10
      },
      {
        "id": 4,
        "created_at": "2016-05-10T10:25:23.381177",
        "text": "werwer",
        "author_id": 1,
        "parent_post_id": 10
      },
      {
        "id": 1,
        "created_at": "2016-05-10T05:25:28.200327",
        "text": "asadasdad",
        "author_id": 1,
        "parent_post_id": 10
      },
      {
        "id": 4,
        "created_at": "2016-05-10T10:25:23.381177",
        "text": "werwer",
        "author_id": 1,
        "parent_post_id": 10
      }
    ]
  }
]

【问题讨论】:

    标签: sql postgresql join data-modeling


    【解决方案1】:

    在所有参与方都加入后进行分组,因此聚合将取决于生成的基数。加入带有答案和 cmets 的帖子会导致它们之间的完全连接,复制所有值。它们需要分开并单独执行,一种方法如下:

    SELECT
        q.*,
        (SELECT json_agg(ac.*)
         FROM (
           SELECT a.*, json_agg(c.*) AS comments
           FROM posts a
           LEFT JOIN comments c ON (a.post_id = c.parent_post_id)
           WHERE a.parent_post_id = q.post_id
           GROUP BY a.post_id
           ) ac
        ) AS answers,
        json_agg(c.*) AS comments --comments on posts of post_id questions
    FROM posts q
    LEFT JOIN comments c ON (q.post_id = c.parent_post_id)
    WHERE q.post_id = 10
    GROUP BY q.post_id;
    

    或者:

    SELECT q.*, qa.answers, qc.comments
    FROM posts q
    LEFT JOIN (
      SELECT ac.parent_post_id, json_agg(ac.*) AS answers
      FROM (
        SELECT ac.*, json_agg(c.*) AS comments
        FROM posts ac
        LEFT JOIN comments c ON (c.parent_post_id = ac.post_id)
        GROUP BY ac.post_id
        ) ac
      GROUP BY ac.parent_post_id
      ) qa ON (qa.parent_post_id = q.post_id)
    LEFT JOIN (
      SELECT c.parent_post_id, json_agg(c.*) AS comments
      FROM comments c
      GROUP BY c.parent_post_id
      ) qc ON (qc.parent_post_id = q.post_id)
    WHERE q.post_id = 10;
    

    【讨论】:

    • 我在终端上从这些查询中收到两条错误消息。第一个用于前者:[error: syntax error at or near "."],第二个用于后者:[error: syntax error at or near "FROM"]。我找不到为什么?我一直在检查以找出答案。
    • LEFT JOIN comments c (q.post_id = c.parent_post_id) 是指LEFT JOIN comments c ON q.post_id = c.parent_post_id
    • @Işık 是的,现在修复了这两个错误
    • 第一个现在可以了,没有错误。我认为最后一个左连接的第二个缺少 ON 。当我添加它时,它说在第 9 行表 q 不能从这部分查询中引用。
    • 它仍然说同样的话。毕竟第一个也没有产生我需要的结果。它不会将答案放在答案中,而是将帖子本身与该帖子上的 cmets 放在答案键中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 1970-01-01
    • 2021-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多