具有查询语法错误的SQLite多重插入

时间:2017-01-10 20:50:42

标签: python sql sqlite

我正在尝试使用python将多行插入到SQLite DB中。我有三张桌子:

UniversityA:

  • ID
  • COURSE_NAME
  • course_code
  • course_prefix

UniversityB:

  • ID
  • COURSE_NAME
  • course_code
  • course_prefix

CourseMap:

  • universityA_id(引用大学A的ID)
  • universityB_id(引用大学B的id)
  • is_flagged(boolean 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()执行多个插入时,我收到语法错误:

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)

我得到的错误是“语法错误:语法无效”,插入符号位于第一个插入符号的布尔is_flagged值之前。

我在executemany()的多重插入语法中遗漏了什么?我的SQLite 3版本是3.10.0。

2 个答案:

答案 0 :(得分:1)

您不能将DDL / DML SQL语句(即SELECT语句)作为参数传递。事实上,这是参数化的非常原因!回想一下Bobby Tables注入问题。参数设计为每次执行的调用接收单个绑定值。

根据您的需要,考虑一个联合交叉连接的已执行语句,您可以使用逗号分隔的SELECT语句或显式CROSS JOIN来完成。以下假设每个查询SELECT仅返回一个 id 值),否则您将附加笛卡尔交叉产品。

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”)的表中,以便有效存储,查询和缩放。

答案 1 :(得分:1)

在SQL中,您可以在VALUES子句中使用多个元组;这需要多次编写子查询:

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

Python 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)

如果这不是您想要更改的内容,则必须单独执行子查询,并将结果提供给executemany