在 table 中查找并创建缺失的行

Finding and creating missing rows in table

您好 postgres 专家,

我有一个应用程序,用户可以在其中投票。我的架构如下所示:

polls table:

id name
1 Favorite fruit

options table:

id poll_id content
1 1 apple
2 1 orange
3 1 grape
4 1 banana

participants table:

id poll_id name
1 1 John
2 1 Jane

votes table:

id poll_id participant_id option_id type
1 1 1 1 yes
2 1 1 3 yes
3 1 2 2 yes

我决定不为 votes table 中的“反对”票创建行,我认为这会“节省 space”,这是一个糟糕的选择。我现在意识到这不是一个好主意,因为将来我想知道用户是否明确投了“否”票,或者是否可能在他们投票后添加了该选项,因此没有选择它的选项。因此,我需要 运行 一个查询,该查询将填充现有 participants votes table 中所有缺失的“否”票。最终结果应如下所示:

votes table:

id poll_id participant_id option_id type
1 1 1 1 yes
2 1 1 3 yes
3 1 2 2 yes
4 1 1 2 no
5 1 1 4 no
6 1 2 1 no
7 1 2 3 no
8 1 2 4 no

我有一个 dbfiddle,其中包含所有数据:

https://dbfiddle.uk/?rdbms=postgres_14&fiddle=7d0f4c83095638cc6006b1d7876d0e01

附带问题: 我是否应该关注此架构中投票的大小 table?我预计它会迅速膨胀到数百万行。 options 作为数组存储在 polls table 中,而 votes 存储在 participants table 中的模式是更好的主意吗?

感谢您的帮助。

您似乎正在寻找 JOIN of participants with options, EXCEPT 已经在 votes 中的行。有多种方法可以做到这一点,但最直接的方法是:

INSERT INTO votes(poll_id, participant_id, option_id, type)
SELECT poll_id, participant_id, option_id, 'no'
FROM (
  SELECT o.poll_id, p.id, o.id
  FROM options o
  JOIN participants p ON o.poll_id = p.poll_id
EXCEPT
  SELECT poll_id, participant_id, option_id
  FROM votes
) AS missing;

或者:

INSERT INTO votes(poll_id, participant_id, option_id, type)
SELECT o.poll_id, p.id, o.id, 'no'
FROM options o
JOIN participants p ON o.poll_id = p.poll_id
WHERE NOT EXISTS (
  SELECT *
  FROM votes
  WHERE poll_id = o.poll_id AND participant_id = p.id AND option_id = o.id
);

或者,假设您已经在 votes 上有 UNIQUE 索引,只需

INSERT INTO votes(poll_id, participant_id, option_id, type)
SELECT o.poll_id, p.id, o.id, 'no'
FROM options o
ON CONFLICT ON CONSTRAINT votes_p_key
DO NOTHING;