web-dev-qa-db-ja.com

asyncpgで複数の行を挿入する最良の方法

複数の行を挿入し、asyncpgでIDを取得したいのですが、2つの方法が見つかりました:1:このようなSQLを生成する

INSERT INTO films (code, title, did, date_prod, kind) VALUES
    ('B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'),
    ('HG120', 'The Dinner Game', 140, DEFAULT, 'Comedy')
RETURNING id;

2:forループでプリペアドステートメントを使用する

values =(('B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'),
        ('HG120', 'The Dinner Game', 140, DEFAULT, 'Comedy'))
stmnt = connection.prepare("INSERT INTO films (code, title, did, date_prod, kind) VALUES $1, $2, $3, $4, $5  RETURNING id")
for val in values:
    stmnt.fetchval(*val)

700 000行で100倍の場合、どちらの方法を選択する必要がありますか、またはこのアプローチを組み合わせる方法はありますか?私は完全に緑なので、私にいくつかのトマトを投げます

10
0sv4

RETURNING句を使用してIDを取得する必要がある場合、複数の値を挿入する最も効率的な方法は次のとおりです。

res = await conn.fetch('''
    INSERT INTO films (code, title, did, date_prod, kind)
    (SELECT
        r.code, r.title, r.did, r.date_prod, r.kind
     FROM
        unnest($1::films[]) as r
    )
    RETURNING id
''', [
    (None, 'B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'),
    (None, 'HG120', 'The Dinner Game', 140, None, 'Comedy')
])

入力として渡すレコード必須はテーブルの形状に対応していることに注意してください。PostgreSQLは入力として任意のレコードをサポートしていないため、既知のレコードタイプを使用する必要があります。挿入しない列をNoneとして渡すだけで、SELECTリターンリストに含めないでください。このメソッドでは、DEFAULTに依存することもできません。挿入された各値は、明示的に指定する必要があります。

7

asyncpgは、多くの行を挿入するための executemany メソッドを提供します。

statement = """INSERT INTO films (code,
                           title, 
                           did, 
                           date_prod, 
                           kind) VALUES($1, $2, $3, $4, $5);"""
await connection.executemany(statement, values)

挿入されたIDを返すために後で説明したようにRETURNINGを使用する必要がある場合は、これが answer です。

6
styvane

一度に多くの行を挿入する別の方法(挿入されたIDが必要ない場合)は、copy_records_to_tableメソッドを使用することです。

data = [
    ("row", 1, "some data"),
    ("row", 2, "more data"),
]
await conn.copy_records_to_table('mytable', records=data)
1
Thane Brimhall