SQL JOIN查询中的重复条目

时间:2016-05-11 01:44:26

标签: sql postgresql join data-modeling

我有三个表帖子评论用户。帖子表包括两种类型的帖子,问题答案。对问题和答案进行评论。我的目的是得到一个单独的问题,对它的评论,答案和对答案的评论。另外,我需要来自users表的用户名作为我提取的每个问题,答案和评论的作者。我正在使用Postgres 9.5,并使用json_agg()函数。

虽然我需要的示例输出应该与第一个类似,但我会重复输入。

我在这里失踪的是什么?正确的分组条款可能是。或者用他们的评论收集答案的子查询不是这样做的方法。当我从评论表上的帖子中注释掉左连接时,我得到了期望的结果而没有对问题的评论。此外,当我取消包含子查询的左连接时,我得到了非预期的非重复结果,并且这也不是我想要的完整数据集。这些是我迄今为止收集的用来解决我的问题的事情。

我需要什么:

[
  {
    "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
      }
    ]
  }
]

1 个答案:

答案 0 :(得分:1)

一旦所有参与方加入,就会发生分组,因此聚合将取决于产生的基数。将帖子与答案和注释连接会导致它们之间完全连接,从而复制所有值。它们需要分开并单独执行,一种方法可以做到以下几点:

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;