psycopg2: 하나의 쿼리로 여러 행을 삽입합니다.
하나의 쿼리로 여러 행을 삽입해야 하므로(행 수는 일정하지 않음) 다음과 같은 쿼리를 실행해야 합니다.
INSERT INTO t (a, b) VALUES (1, 2), (3, 4), (5, 6);
내가 아는 유일한 방법은
args = [(1,2), (3,4), (5,6)]
args_str = ','.join(cursor.mogrify("%s", (x, )) for x in args)
cursor.execute("INSERT INTO t (a, b) VALUES "+args_str)
하지만 좀 더 간단한 방법을 원해요
저는 다른 도시에 있는 서버에 여러 줄을 삽입하는 프로그램을 만들었습니다.
하는 것이 되었습니다.executemany
★★★★★★★★★★★★★★★★★★★★★★★★★.tup
2000년입니다.을 사용하면 걸렸습니다.
args_str = ','.join(cur.mogrify("(%s,%s,%s,%s,%s,%s,%s,%s,%s)", x) for x in tup)
cur.execute("INSERT INTO table VALUES " + args_str)
및 이 방법을 사용할 경우 2분:
cur.executemany("INSERT INTO table VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s)", tup)
Psycopg 2.7의 새로운 방법:
data = [(1,'x'), (2,'y')]
insert_query = 'insert into t (a, b) values %s'
psycopg2.extras.execute_values (
cursor, insert_query, data, template=None, page_size=100
)
Psycopg 2.6에서는 버마적인 방법:
data = [(1,'x'), (2,'y')]
records_list_template = ','.join(['%s'] * len(data))
insert_query = 'insert into t (a, b) values {}'.format(records_list_template)
cursor.execute(insert_query, data)
설명:삽입할 데이터가 다음과 같이 튜플 리스트로 제공되는 경우
data = [(1,'x'), (2,'y')]
이미 필요한 포맷으로 되어 있습니다.
values
의insert
은 기록합니다.insert into t (a, b) values (1, 'x'),(2, 'y')
Psycopg
Python을tuple
Postgresql로 †record
필요한 작업은 psycopg에 의해 채워질 레코드 목록 템플릿을 제공하는 것뿐입니다.
# We use the data list to be sure of the template length
records_list_template = ','.join(['%s'] * len(data))
해서 에에 the and에 and and and the the 。insert
insert_query = 'insert into t (a, b) values {}'.format(records_list_template)
★★★★의 insert_query
표시
insert into t (a, b) values %s,%s
의 ★★★★★★★★★★★★★★★★★★★★★★★★★.Psycopg
치환
cursor.execute(insert_query, data)
또는 서버에 송신되는 것을 테스트하는 것만으로
print (cursor.mogrify(insert_query, data).decode('utf8'))
출력:
insert into t (a, b) values (1, 'x'),(2, 'y')
psycopg2 2.7 업데이트:
인 래식 theexecutemany()
는 @ant32의 실장(「module」이라고 불린다)보다 약 60배 느립니다.https://www.postgresql.org/message-id/20170130215151.GA7081%40deb76.aryehleib.com
2.되어 psycopg2라고 .execute_values()
:
from psycopg2.extras import execute_values
execute_values(cur,
"INSERT INTO test (id, v1, v2) VALUES %s",
[(1, 2, 3), (4, 5, 6), (7, 8, 9)])
이전 답변:
합니다.VALUES
합니다.execute()
보다 약 .executemany()
이지, . . . . . . . . . . . . . 。executemany()
을 할 수 있습니다.INSERT
★★★★★★★★★★★★★★★★★★.
2ant32에서는 하게 동작합니다. Python에서는 지지에 에에3 but butcursor.mogrify()
cursor.execute()
스트링 중 를 사용합니다.또, 「바이트 또는 스트링」은 「바이트 또는 「바이트 또는 스트링」이 됩니다.','.join()
str
★★★★★★ 。
Python 에서는 "Python 3"을 추가하여 @..decode('utf-8')
:
args_str = ','.join(cur.mogrify("(%s,%s,%s,%s,%s,%s,%s,%s,%s)", x).decode('utf-8') for x in tup)
cur.execute("INSERT INTO table VALUES " + args_str)
바이트(「」를 사용)b''
★★★★★★★★★★★★★★★★★」b""
)개요:
args_bytes = b','.join(cur.mogrify("(%s,%s,%s,%s,%s,%s,%s,%s,%s)", x) for x in tup)
cur.execute(b"INSERT INTO table VALUES " + args_bytes)
cursor.copy_from은 대량 삽입을 위한 지금까지 발견된 솔루션 중 가장 빠른 솔루션입니다.여기 Iterator File이라는 클래스를 포함하는 Gist를 소개합니다.이 클래스는 문자열을 생성하는 반복기를 파일처럼 읽을 수 있도록 합니다.제너레이터 식을 사용하여 각 입력 레코드를 문자열로 변환할 수 있습니다.그래서 해결책은
args = [(1,2), (3,4), (5,6)]
f = IteratorFile(("{}\t{}".format(x[0], x[1]) for x in args))
cursor.copy_from(f, 'table_name', columns=('a', 'b'))
이 작은 크기의 Arg라면 속도 차이는 크지 않지만 수천 개 이상의 행을 처리할 때 속도가 크게 향상됩니다.또한 대용량 쿼리 문자열을 작성하는 것보다 메모리 효율이 높습니다.반복기는 한 번에 하나의 입력 레코드만 메모리에 저장할 수 있으며, 쿼리 문자열을 구축하면 Python 프로세스나 Postgres에서 메모리가 부족해질 수 있습니다.
Postgresql.org에 있는 Psycopg2 튜토리얼 페이지의 일부(하단 참조):
마지막으로 보여드리고 싶은 항목은 사전을 사용하여 여러 행을 삽입하는 방법입니다.다음과 같은 경우:
namedict = ({"first_name":"Joshua", "last_name":"Drake"},
{"first_name":"Steven", "last_name":"Foo"},
{"first_name":"David", "last_name":"Bar"})
다음을 사용하여 사전의 세 행을 모두 쉽게 삽입할 수 있습니다.
cur = conn.cursor()
cur.executemany("""INSERT INTO bar(first_name,last_name) VALUES (%(first_name)s, %(last_name)s)""", namedict)
코드가 많이 저장되지는 않지만 확실히 좋아 보입니다.
이 모든 기술은 Postgres 용어로는 '확장 삽입'으로 불리며, 2016년 11월 24일 현재도 psychopg2의 executemany() 및 이 스레드에 나열된 다른 모든 메서드보다 훨씬 빠릅니다(이 답변에 앞서 시도했습니다).
다음은 cur.mogrify를 사용하지 않고 알기 쉽게 하기 위한 코드입니다.
valueSQL = [ '%s', '%s', '%s', ... ] # as many as you have columns.
sqlrows = []
rowsPerInsert = 3 # more means faster, but with diminishing returns..
for row in getSomeData:
# row == [1, 'a', 'yolo', ... ]
sqlrows += row
if ( len(sqlrows)/len(valueSQL) ) % rowsPerInsert == 0:
# sqlrows == [ 1, 'a', 'yolo', 2, 'b', 'swag', 3, 'c', 'selfie' ]
insertSQL = 'INSERT INTO "twitter" VALUES ' + ','.join(['(' + ','.join(valueSQL) + ')']*rowsPerInsert)
cur.execute(insertSQL, sqlrows)
con.commit()
sqlrows = []
insertSQL = 'INSERT INTO "twitter" VALUES ' + ','.join(['(' + ','.join(valueSQL) + ')']*len(sqlrows))
cur.execute(insertSQL, sqlrows)
con.commit()
단, copy_from()을 사용할 수 있는 경우에는 copy_from'을 사용해야 합니다.
저는 몇 년 전부터 위의 ant32의 답변을 사용하고 있습니다. 나는 한다는 것을 왜냐하면 비단뱀 3의 오류이기 때문이다.mogrify
이치노
코드 python 3을 호환하기 위한 간단한 솔루션은 bythe 문자열로 명시적으로 변환하는 것입니다.
args_str = b','.join(cur.mogrify("(%s,%s,%s,%s,%s,%s,%s,%s,%s)", x) for x in tup)
cur.execute(b"INSERT INTO table VALUES " + args_str)
execute any accept tuples 배열
https://www.postgresqltutorial.com/postgresql-python/insert/
""" array of tuples """
vendor_list = [(value1,)]
""" insert multiple vendors into the vendors table """
sql = "INSERT INTO vendors(vendor_name) VALUES(%s)"
conn = None
try:
# read database configuration
params = config()
# connect to the PostgreSQL database
conn = psycopg2.connect(**params)
# create a new cursor
cur = conn.cursor()
# execute the INSERT statement
cur.executemany(sql,vendor_list)
# commit the changes to the database
conn.commit()
# close communication with the database
cur.close()
except (Exception, psycopg2.DatabaseError) as error:
print(error)
finally:
if conn is not None:
conn.close()
cursor.copy from 솔루션은 @jopseph에 의해 제공됩니다.sheedy(https://stackoverflow.com/users/958118/joseph-sheedy) 위의 https://stackoverflow.com/a/30721460/11100064)는 정말 빠른 속도입니다.
그러나 그가 제시한 예는 필드 수가 많은 레코드에는 일반적으로 사용할 수 없기 때문에 올바르게 사용하는 방법을 파악하는 데 시간이 걸렸습니다.
은 다음과(Iterator File)로 인스턴스화해야 .r
는 딕트 목록입니다.각 딕트는 레코드입니다).
f = IteratorFile("{0}\t{1}\t{2}\t{3}\t{4}".format(r["id"],
r["type"],
r["item"],
r["month"],
r["revenue"]) for r in records)
하기 위해 먼저 플레이스 홀더를 행 .「 」 。"{}\t{}\t{}....\t{}"
그런 다음 사용.format()
필드 값을 입력합니다.*list(r.values())) for r in records
:
line = "\t".join(["{}"] * len(records[0]))
f = IteratorFile(line.format(*list(r.values())) for r in records)
여기서 gist의 기능을 완성합니다.
이 질문이 게시된 이후 execute_module이 psycopg2에 추가되었습니다.
execute_values보다 빠릅니다.
또 하나의 적절하고 효율적인 접근법은 json 객체의 배열인 1개의 인수로 삽입할 행을 전달하는 것입니다.
예: 인수 통과:
[ {id: 18, score: 1}, { id: 19, score: 5} ]
어레이입니다.이 어레이에는 내부에 임의의 양의 객체가 포함될 수 있습니다.SQL은 다음과 같습니다.
INSERT INTO links (parent_id, child_id, score)
SELECT 123, (r->>'id')::int, (r->>'score')::int
FROM unnest($1::json[]) as r
주의: 게시물은 json을 지원하기에 충분히 새로운 것이어야 합니다.
SQL Chemy를 사용하는 경우, SQL Chemy는 단일 스테이트먼트에 대해 여러 행의 절을 생성할 수 있기 때문에 스트링을 수작업으로 만들 필요가 없습니다.
rows = []
for i, name in enumerate(rawdata):
row = {
'id': i,
'name': name,
'valid': True,
}
rows.append(row)
if len(rows) > 0: # INSERT fails if no rows
insert_query = SQLAlchemyModelName.__table__.insert().values(rows)
session.execute(insert_query)
@ant32부터
def myInsertManyTuples(connection, table, tuple_of_tuples):
cursor = connection.cursor()
try:
insert_len = len(tuple_of_tuples[0])
insert_template = "("
for i in range(insert_len):
insert_template += "%s,"
insert_template = insert_template[:-1] + ")"
args_str = ",".join(
cursor.mogrify(insert_template, x).decode("utf-8")
for x in tuple_of_tuples
)
cursor.execute("INSERT INTO " + table + " VALUES " + args_str)
connection.commit()
except psycopg2.Error as e:
print(f"psycopg2.Error in myInsertMany = {e}")
connection.rollback()
하나의 삽입 스테이트멘에 여러 행을 삽입하는 경우(ORM을 사용하지 않는 경우) 사전 목록을 사용하는 것이 가장 쉬운 방법입니다.다음은 예를 제시하겠습니다.
t = [{'id':1, 'start_date': '2015-07-19 00:00:00', 'end_date': '2015-07-20 00:00:00', 'campaignid': 6},
{'id':2, 'start_date': '2015-07-19 00:00:00', 'end_date': '2015-07-20 00:00:00', 'campaignid': 7},
{'id':3, 'start_date': '2015-07-19 00:00:00', 'end_date': '2015-07-20 00:00:00', 'campaignid': 8}]
conn.execute("insert into campaign_dates
(id, start_date, end_date, campaignid)
values (%(id)s, %(start_date)s, %(end_date)s, %(campaignid)s);",
t)
보시는 바와 같이 쿼리는 1개만 실행됩니다.
INFO sqlalchemy.engine.base.Engine insert into campaign_dates (id, start_date, end_date, campaignid) values (%(id)s, %(start_date)s, %(end_date)s, %(campaignid)s);
INFO sqlalchemy.engine.base.Engine [{'campaignid': 6, 'id': 1, 'end_date': '2015-07-20 00:00:00', 'start_date': '2015-07-19 00:00:00'}, {'campaignid': 7, 'id': 2, 'end_date': '2015-07-20 00:00:00', 'start_date': '2015-07-19 00:00:00'}, {'campaignid': 8, 'id': 3, 'end_date': '2015-07-20 00:00:00', 'start_date': '2015-07-19 00:00:00'}]
INFO sqlalchemy.engine.base.Engine COMMIT
마지막으로 SQLalchemy 1.2 버전에서는 이 새로운 구현이 psycopg2를 사용하기 위해 추가되었습니다.use_batch_mode=True로 엔진을 초기화할 때 executemany 대신 extra.batch_model()을 사용합니다.
engine = create_engine(
"postgresql+psycopg2://scott:tiger@host/dbname",
use_batch_mode=True)
http://docs.sqlalchemy.org/en/latest/changelog/migration_12.html#change-4109
SQLalchmey를 사용하면 SQL과 psycopg2의 다른 조합과 직접 SQL을 함께 사용할 필요가 없습니다.
aiopg 사용 - 아래 스니펫은 완벽하게 작동합니다.
# items = [10, 11, 12, 13]
# group = 1
tup = [(gid, pid) for pid in items]
args_str = ",".join([str(s) for s in tup])
# insert into group values (1, 10), (1, 11), (1, 12), (1, 13)
yield from cur.execute("INSERT INTO group VALUES " + args_str)
언급URL : https://stackoverflow.com/questions/8134602/psycopg2-insert-multiple-rows-with-one-query
'sourcecode' 카테고리의 다른 글
mysql 설명 분석이 안되는 이유는 무엇입니까? (0) | 2023.01.30 |
---|---|
java.displaces를 클릭합니다.날짜 형식 yyy-mm-dd에서 mm-dd-yyy로 변환 (0) | 2023.01.30 |
PHP에서 다차원 어레이를 단순 어레이로 "평탄화"하는 방법은 무엇입니까? (0) | 2023.01.30 |
테스트 실패: Jest + Vue 3 + Vuex + Typescript: TypeError: 정의되지 않은 속성 'then'을 읽을 수 없습니다. (0) | 2023.01.30 |
중첩된 사전의 값을 가져오는 안전한 방법 (0) | 2023.01.30 |