2012-01-07 10 views
4

既存のデータベースにデータを挿入または更新するために、迅速な一時的なSQLファイルを使用することがよくあります。 SQLは通常、開発者によって書かれ、開発システムでテストされた後、psql -U dbuser dbname < file.sqlで本番DBにインポートされます。PostgreSQLのMySQLの変数を置き換えますか?

A(ささい)の例では、次のようになります。

INSERT INTO employees (
    company_id, 
    name, 
    position, 
    created_by, 
    last_modified_by 
) VALUES 
(
    (SELECT id FROM companies WHERE name = 'Acme Fellowship'), 
    'Frodo Baggins', 
    'Ring bearer', 
    (SELECT id FROM users WHERE login = 'admin'), 
    (SELECT id FROM users WHERE login = 'admin') 
), 
(
    (SELECT id FROM companies WHERE name = 'Acme Fellowship'), 
    'Samwise Gamgee', 
    'Rope bearer', 
    (SELECT id FROM users WHERE login = 'admin'), 
    (SELECT id FROM users WHERE login = 'admin') 
), 
(
    (SELECT id FROM companies WHERE name = 'Acme Fellowship'), 
    'Peregrin Took', 
    'Ent rider', 
    (SELECT id FROM users WHERE login = 'admin'), 
    (SELECT id FROM users WHERE login = 'admin') 
); 

これは動作しますが、サブクエリでの反復コードがたくさんあります。​​とusers.idの関連する値を一時変数に格納する方が良いでしょう(より効率的で、エラーが起こりにくい)。この解釈された例では、パフォーマンスの差は最小限に抑えられますが、実際にはより複雑なクエリと更新があり、更新/挿入されるレコードは3つ以上です。

MySQLのために書かれた同じ例は次のようになります。

SELECT @company_id := id FROM companies WHERE name = 'Acme Fellowship'; 
SELECT @admin_id := id FROM users WHERE login = 'admin'; 
INSERT INTO employees (
    company_id, 
    name, 
    position, 
    created_by, 
    last_modified_by 
) VALUES 
(@company_id, 'Frodo Baggins', 'Ring bearer', @admin_id, @admin_id), 
(@company_id, 'Samwise Gamgee', 'Rope bearer', @admin_id, @admin_id), 
(@company_id, 'Peregrin Took', 'Ent rider', @admin_id, @admin_id); 

は、PostgreSQLで似た何かを達成する方法はありますか?

私が見てきたどのような:のみ手順で使用することができます(私たちはまだ実行している:ストアクエリに使用することはできませんが、

  • がplpgsqlが結果:(\set付き)

    • psqlのセッション変数8.4)
    • 一時テーブル:私はPostgresのための直接対応がない場合、あなたはwをどう思いますか

    醜いと複雑な文を作成することなく、それらを使用する方法を見ることができませんこの種の更新ファイルを作成するには、少なくとも不器用な方法ですか? SELECTで

  • 答えて

    2

    は値一度を照会するCTEsまたはサブクエリの使用を検討し、それらを何度も挿入しました。
    このようにして、MySQLスタイル変数を標準SQLに置き換えることができます。

    INSERT INTO employees 
         (company_id, name, position, created_by, last_modified_by) 
    SELECT c.id  , name, position, u.id  , u.id 
    FROM (SELECT id FROM companies WHERE name = 'Acme Fellowship') c 
        ,(SELECT id FROM users WHERE login = 'admin') u 
        ,(VALUES 
         ('Frodo Baggins', 'Ring bearer') 
         ,('Samwise Gamgee', 'Rope bearer') 
         ,('Peregrin Took', 'Ent rider') 
        ) v(name, position) 
    

    companies.nameusers.loginが、実際には、一意であると仮定すると。複数のヒットが挿入される行を増やします。
    INSERT command in the manualについて読んでください。ここで


    は、誰でも簡単に見を持っているしたい場合には、一時テーブルと私のテストのセットアップです:

    CREATE TEMP TABLE companies (id int, name text); 
    INSERT INTO companies VALUES (17, 'Acme Fellowship'); 
    
    CREATE TEMP TABLE users (id int, login text); 
    INSERT INTO users VALUES (9, 'admin'); 
    
    CREATE TEMP TABLE employees (
    company_id int 
    ,name text 
    ,position text 
    ,created_by int 
    ,last_modified_by int); 
    
    +0

    非常に優雅に、ありがとうございます。 – Zilk

    +2

    CTEはバージョン8.4では動作しませんが、INSERTをサポートしていません。これには少なくともバージョン9.1が必要です。 –

    +0

    @FrankHeikens:良い点。そのため、私はここでサブクエリを使用しました。 –

    4

    利用価値は()、それが動作するはずです:

    INSERT INTO employees (
        company_id, 
        name, 
        position, 
        created_by, 
        last_modified_by 
    ) 
    SELECT 
        (SELECT id FROM companies WHERE name = 'Acme Fellowship'), 
        name, 
        position, 
        (SELECT id FROM users WHERE login = 'admin'), 
        (SELECT id FROM users WHERE login = 'admin') 
    FROM 
        (VALUES -- all your new content here 
         ('Frodo Baggins', 'Ring bearer'), 
         ('Samwise Gamgee', 'Rope bearer'), 
         ('Peregrin Took', 'Ent rider') 
        ) content(name, position); -- use some aliases to make it readable 
    
    1

    は、これは古い質問ですが、私は文を使用して使用することが私の人生が容易になっていることが見つかりました: )

    WITH c AS (
        SELECT company_id, 
        FROM companies 
        WHERE name = 'Acme Fellowship' 
    ), u AS (
        SELECT * 
        FROM users 
        WHERE login = 'admin' 
    ), n AS (
        SELECT * 
        FROM 
         (VALUES -- all your new content here 
          ('Frodo Baggins', 'Ring bearer'), 
          ('Samwise Gamgee', 'Rope bearer'), 
          ('Peregrin Took', 'Ent rider') 
         ) content(name, position) 
    ) 
    INSERT INTO employees (
        company_id, 
        name, 
        position, 
        created_by, 
        last_modified_by 
    ) 
    SELECT c.company_id, n.name, n.position, u.id, u.id 
    FROM c, u, n 
    
    関連する問題