我如何循环插入查询?

how can i loop insert query?

我有这样的问题:我需要优化应用程序,使用 db (postgreSQL),table 看起来像这样:

CREATE TABLE voter_count(
                    id SERIAL, 
                    name VARCHAR NOT NULL, 
                    birthDate DATE NOT NULL, 
                    count INT NOT NULL, 
                    PRIMARY KEY(id), 
                    UNIQUE (name, birthDate))

我有超过一千个这样的选民,我需要把他们都存入数据库,但其中有几个重复的可以投票多次(从2到无穷大),我需要,当遇到这样的副本时, 增加现有的计数字段(对于具有相同姓名和出生日期的选民)。之前只是查了下table里面有没有这样的voter,如果有就找,增加计数。

但是这个程序工作的时间太长了,我尝试通过MULTI INSERT来完成,并使用ON CONFLICT DO UPDATE来增加计数, 但是我得到一个错误,然后我问了一个关于 Whosebug 的问题,我被要求通过一个循环,但是在 PostgreSQL 中做很多插入。

INSERT INTO voter_count(name, birthdate, count) 
VALUES 
('Ivan', '1998-08-05', 1), 
('Sergey', '1998-08-29', 1), 
('Ivan', '1998-08-05', 1) 
ON CONFLICT (name, birthdate) DO UPDATE SET count = (voter_count.count + 1)

问题:如何通过 PostgreSQL 在循环中执行 INSERT。

可能最好的选择是在没有主键的 table 中的所有数据之前插入,例如:

CREATE TABLE voter_count_with_duplicates(
                name VARCHAR NOT NULL, 
                birthDate DATE NOT NULL)

然后用一条语句插入数据:

INSERT INTO voter_count (name, birthDate, count)
SELECT name, birthDate, COUNT(*)
FROM voter_count_with_duplicates
GROUP BY name, birthDate

请注意,如果数据位于结构化文本文件(例如 CSV 文件)中,则可以使用单个 COPY 语句将所有数据插入 voter_count_with_duplicates

如果您必须插入(大量)新数据且 table 已经填充,则有几种可能性。一种是使用评论中的解决方案。另一个是执行更新和插入:

 WITH present_tuples AS 
  (SELECT name, birthDate, COUNT(*) AS num_of_new_votes
   FROM voter_count_with_duplicates d JOIN voter_count c ON
         v.name = d.name and v.birthDate = d.birthDate
   GROUP BY name, birthDate)
 UPDATE voter_count SET count = count + num_of_new_votes
           FROM present_tuples
           WHERE present_tuples.name = voter_count.name
             AND present_tuples.birthDate = voter_count.birthDate;

WITH new_tuples AS 
  (SELECT name, birthDate, COUNT(*) AS votes
   FROM voter_count_with_duplicates d 
   WHERE NOT EXISTS SELECT * 
                    FROM voter_count c
                    WHERE v.name = d.name and v.birthDate = d.birthDate
   GROUP BY name, birthDate)
INSERT INTO voter_count (name, birthDate, count)
SELECT name, birthDate, votes
FROM new_tuples;

您想要实现的目标通俗地称为更新插入;插入行,如果不存在,则更新。为此使用的操作是 MERGE.

您要合并到现有 table 中的数据集是按名称和日期分组的值的总和,以及您想要 insert/add。

MERGE INTO voter_count vc
USING 
(
  SELECT name, birthdate, SUM(cnt) as total
  FROM 
  (
    VALUES 
      ('Ivan', DATE '1998-08-05', 1), 
      ('Sergey', DATE '1998-08-29', 1), 
      ('Ivan', DATE '1998-08-05', 1) 
  ) input_data (name, birthdate, cnt)
  GROUP BY name, birthdate
) data ON (data.name = vc.name and data.birthdate = vc.birthdate)
when not matched 
  insert (name, birthdate, count) values (data.name, data.birthdate, data.total)
when matched
  update set count = count + data.total;