2017-01-10 12 views
0

複数の行をPythonでSQLite DBに挿入しようとしています。SQLite複数の挿入でクエリ構文エラー

UniversityA:

  • ID
  • COURSE_NAME
  • course_code
  • course_prefix

UniversityB:私は3つのテーブルを持っている

  • ID
  • COURSE_NAME
  • course_code
  • course_prefix

CourseMap:

  • universityA_id(universityAからの参照番号)
  • universityB_id(universityBからの参照番号)
  • はis_flagged(ブール値0/1)

私はこの構文で簡単にCourseMapテーブルに単一のレコードを追加することができます。

cur.execute('INSERT INTO CourseMap (universityA_id, universityB_id, is_flagged) VALUES ((SELECT id from universityA WHERE course_code=301 AND course_prefix="AERO"), (SELECT id from universityB WHERE course_code=101 AND course_prefix="ARCH"), 0)') 

をしかし、私はexecutemany()を使用して複数の挿入を実行するために、リストにこの文を組み込むしようとすると、私は構文エラーを取得します:最初の挿入時に右ブールis_flagged値の前に配置キャレットと、:私は取得しています

equivs = [ 
    ((SELECT id from universityA WHERE course_code=301 AND course_prefix="AERO"), (SELECT id from universityB WHERE course_code=101 AND course_prefix="ARCH"), 0), 
    ((SELECT id from universityA WHERE course_code=301 AND course_prefix="AERO"), (SELECT id from universityB WHERE course_code=101 AND course_prefix="ARCH"), 0), 
    ((SELECT id from universityA WHERE course_code=301 AND course_prefix="AERO"), (SELECT id from universityB WHERE course_code=101 AND course_prefix="ARCH"), 0) 
] 

# Fill the table 
cur.executemany('INSERT INTO courseMap (universityA_id, universityB_id, is_flagged) VALUES (?,?,?)', equivs) 

エラーは、「無効な構文構文エラー」です。

executemany()に複数の挿入構文がありますか?私のSQLite 3のバージョンは3.10.0です。

+0

'equivs'宣言のselect文は文字列であるはずですか? – glibdud

+0

私が考えているのは、プラグインされるINSERTステートメントが文字列であるためではないということです。「equivs」の項目は引用符で囲まなければなりませんか? – Marcatectura

+0

はい。私はそれが 'executemany'ステートメントにも届く前に、どのように構文エラーを*得られなかったか分かりません。 – glibdud

答えて

1

DDL/DML SQL文(つまり、SELECT文)をパラメータとして渡すことはできません。実際には、それは非常に理由パラメータ化です! Bobby Tables注射の問題を思い出してください。パラメータは、実行された呼び出しごとに単一のバインドされた値を受け取るように設計されています。

あなたの必要に応じて、カンマ区切りSELECTステートメントまたは明示的なCROSS JOINで行うことができるユニオンクロスジョイントの1つの実行文を考慮してください。以下の各クエリでは、SELECTidの値を1つだけ返します。そうでない場合は、デカルトクロス商品が追加されます。

INSERT INTO CourseMap (universityA_id, universityB_id, is_flagged) 

SELECT * FROM 
    (SELECT id from universityA WHERE course_code=301 AND course_prefix="AERO"), 
    (SELECT id from universityB WHERE course_code=101 AND course_prefix="ARCH"), (SELECT 0) 

UNION ALL 

SELECT * FROM 
    (SELECT id from universityA WHERE course_code=301 AND course_prefix="AERO"), 
    (SELECT id from universityB WHERE course_code=101 AND course_prefix="ARCH"), (SELECT 0) 

UNION ALL 

SELECT * FROM 
    (SELECT id from universityA WHERE course_code=301 AND course_prefix="AERO"), 
    (SELECT id from universityB WHERE course_code=101 AND course_prefix="ARCH"), (SELECT 0) 

はさておき - ベストプラクティスから二大学のものを外れるような構造化されたテーブルを複製するように両方のテーブルは、効率的なストレージのためのインジケータフィールド(「A」または「B」)と一つに付加することができるように、このスキーマを再検討します、クエリ、およびスケーリング

+0

なぜ私はINSERT内にサブクエリを持つ単一の行を挿入できるのか混乱していますが、複数の行で同じことをすることはできませんでした。 – Marcatectura

+0

このソリューションが示すように、パラメータなしでSQL文全体が正常に実行されました。失敗した試行は、SQLステートメントをパラメーターとして渡そうとしました。さらに、パラメータは単独で評価されるのではなく、準備されたステートメントにバインドされます。 SQL文を準備し、値を@CLとしてタプルのリストとして渡します。ここでのように、ユニオンのクロス・ジョイントを使って、一度にすべてを見せたり、 – Parfait

1

SQLでは、VALUES句に複数のタプルを使用できます。これは、サブクエリを複数回書き込むことが必要です。

INSERT INTO CourseMap (universityA_id, universityB_id, is_flagged) 
VALUES ((SELECT ...), (SELECT ...), 0), 
     ((SELECT ...), (SELECT ...), 0), 
     ((SELECT ...), (SELECT ...), 0); 

Pythonのexecutemany()は異なるパラメータ値で同じの文を複数回実行します。それはあなたが変更したいものでない場合は、個別にサブクエリを実行し、executemanyに、その結​​果を与える必要があり、

args = [ (301, "AERO", 101, "ARCH"), (...) ] 
db.executemany("""INSERT INTO CourseMap (universityA_id, universityB_id, is_flagged) 
        VALUES ((SELECT id from universityA WHERE course_code=? AND course_prefix=?), 
          (SELECT id from universityB WHERE course_code=? AND course_prefix=?), 
          0)""", args) 

:だからあなたが変えることができる唯一のことは、実際のサブクエリで使用される値です。