我有一个超过80行的原始SQL查询,结果我无法使用查询集重现。我现在想要使这个查询与SQLite和PostgreSQL兼容,因此它可以在开发和生产环境中运行。
是否有任何建议或内置方式可以继续?
因此,例如,我得到了这个PostgreSQL语法错误:
operator does not exist: boolean = integer
我调整了语法并使用了一些条件来为每个案例获取正确的SQL字符串,但这对我来说感觉不对:
db_engine = ''
engine = settings.DATABASES['default']['ENGINE']
if re.match('.*sqlite3$', engine):
db_engine = 'sqlite3'
elif re.match('.*psycopg2$', engine):
db_engine = 'postgresql'
elif re.match('.*mysql$', engine):
db_engine = 'mysql'
cursor = connection.cursor()
cursor.execute("""
... some big query here ...
WHERE 1=1
AND some_boolean_field = %(value)s
""" % {
'value': 'TRUE' if db_engine == 'postgresql' else '1'
})
答案 0 :(得分:2)
SQLite doesn't have boolean
。因此,如果您想要在两个数据库中都能正常运行的查询,我建议您在编写原始SQL时避免使用boolean
类型。
boolean
实际上并没有给你带来任何好处,除非你有很多布尔字段打包在一起,因为它们每个都已经有一个字节,并且由于对齐原因而倾向于填充到一个字。
观察原始类型尺寸:
regress=> SELECT pg_column_size(TRUE), pg_column_size(SMALLINT '1');
pg_column_size | pg_column_size
----------------+----------------
1 | 2
(1 row)
并且在考虑行标题之后存在相当小的差异:
regress=> SELECT
pg_column_size( ROW(SMALLINT '1', SMALLINT '1', SMALLINT '0', SMALLINT '1') ),
pg_column_size( ROW(true, true, false, true) );
pg_column_size | pg_column_size
----------------+----------------
32 | 28
(1 row)
这是四个连续布尔字段的最佳值。实际上,对齐限制往往意味着你大多数时候也可能只使用一小部分。
如果你想使用boolean然后与SQLite一起玩,你需要将所有内容都转换成整数。这将是SQLite上的无操作(因此它将在那里工作)并且在PostgreSQL上将boolean转换为int。
AND CAST(some_boolean_field AS integer) = CAST (%(value)s AS integer)
这可以让你摆脱PostgreSQL布尔的特殊情况;只需传递1表示true / 0表示false并使用:
AND CAST(some_boolean_field AS integer) = %(value)s
....或者,当然,您可以在开发和生产中使用相同的引擎测试PostgreSQL。这样,当你推动改变时,你不会得到令人讨厌的惊喜。我写了一些关于调整PostgreSQL安装的方法,用于抛弃测试in this earlier post。