首页 > 解决方案 > 我如何循环插入查询?

问题描述

我有一个这样的问题:我需要优化应用程序,用db(postgreSQL),表是这样的:

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 到无穷大),当遇到这样的副本时,我需要,增加现有的计数字段(对于具有相同姓名和出生日期的选民)。之前我只是检查了表中是否有这样的选民,如果有,然后找到它并增加计数。

但是程序运行时间太长了,我尝试通过 MULTI INSERT 来完成,并使用 ON CONFLICT DO UPDATE 来增加计数,但是我得到一个错误,然后我在 stackoverflow 上问了一个问题,并且有人提议我做很多通过循环插入,但在 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 循环插入。

标签: sqlpostgresqlpostgresql-13

解决方案


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

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 文件)中的数据,则可以voter_count_with_duplicates使用单个COPY语句将所有数据插入其中。

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

 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;

推荐阅读