【问题标题】:Cannot Query Array of Integers in Postgres无法在 Postgres 中查询整数数组
【发布时间】:2016-07-15 23:01:36
【问题描述】:

已将列类型从 HSTORE 迁移到 JSONB,并且正在使用此 sn-p 代码...

from sqlalchemy.dialects.postgresql import ARRAY, JSONB

if employment_type:
        base = base.filter(Candidate.bio["employment_type"].cast(ARRAY).contains(employment_type))  

我收到了这个错误...

127.0.0.1 - - [28/Mar/2016 12:25:13] "GET /candidate_filter/?employment_type_3=true HTTP/1.1" 500 -
Traceback (most recent call last):
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/surajkapoor/Desktop/lhv-talenttracker/app/views.py", line 660, in investor_filter
    base = base.filter(Candidate.bio["employment_type"].cast(ARRAY).contains(employment_type))
  File "/Library/Python/2.7/site-packages/sqlalchemy/dialects/postgresql/json.py", line 93, in cast
    return self.astext.cast(type_)
  File "/Library/Python/2.7/site-packages/sqlalchemy/dialects/postgresql/json.py", line 95, in cast
    return sql.cast(self, type_)
  File "<string>", line 2, in cast

  File "/Library/Python/2.7/site-packages/sqlalchemy/sql/elements.py", line 2314, in __init__
    self.type = type_api.to_instance(type_)
  File "/Library/Python/2.7/site-packages/sqlalchemy/sql/type_api.py", line 1142, in to_instance
    return typeobj(*arg, **kw)
TypeError: __init__() takes at least 2 arguments (1 given)

Candidate.bio["employment_type"] 是一个整数数组,我只是想查询其中包含特定整数的所有行。

此外,当调用 Integer 时,.cast() 可以在同一列上完美运行...

if internship:
    base = base.filter(Candidate.bio["internship"].cast(Integer) == 1)  

【问题讨论】:

  • 你试过没有cast,即Candidate.bio["employment_type"].contains(employment_type)吗?从文档中,contains 也应该适用于数组 - “测试键(或数组)是否是参数 jsonb 表达式的键的超集/包含。”
  • @LymanZerga 是的,尝试不使用演员表...我得到 DataError: (psycopg2.DataError) invalid input syntax for integer: "%" LINE 3: ...!= 0 AND ((candidate .bio -> 'location_work') LIKE '%' + 2 ||...
  • 你能发布一些示例数据行吗?

标签: arrays postgresql sqlalchemy


【解决方案1】:

SqlAlchemy 可能难以构造 where 子句,因为它无法确定 bio-&gt;'employment_type' 是什么类型。

如果从String 对象调用contains 方法,它将生成LIKE 子句,但对于JSONBARRAY,则需要生成@&gt; 运算符。

要为 SqlAlchemy 提供必要的提示,请在任何地方使用显式强制转换,即将查询编写为

from sqlalchemy import cast

if employment_type:
    casted_field = Candidate.bio['employment_type'].cast(JSONB)
    casted_values = cast(employment_type, JSONB)
    stmt = base.filter(casted_field.contains(casted_values))

【讨论】:

  • @Suraj Kapoor 你不需要将employment_type 转换为JSONB。
  • @SurajKapoor,谢谢。我刚刚尝试过,在我的机器上,如果将列表传递给包含,则不需要强制转换,但需要整数转换。您使用的是什么版本的 sqlalchemy / python?我在 python 3.4.3 sqlalchemy 1.0.11
  • 尝试不进行强制转换,但不起作用。我在 Python 2.7 和 Sqlalchemy 0.9.8
  • @HaleemurAli ps 我认为强制转换是必要的,因为该列是从 hstore 类型迁移而来的
【解决方案2】:

在我的示例中,我有一个名为 bioJSONB 列,其中包含以下数据:

{"employment_type": [1, 2, 3]}

编辑:转换为JSONB 有效:

>>> from sqlalchemy.dialects.postgresql import JSONB
>>> employment_type = 2

>>> query = (
...     session.query(Candidate)
...     .filter(Candidate.bio['employment_type'].cast(JSONB).contains(employment_type)))

>>> query.one().bio
{"employment_type": [1, 2, 3]}

原答案:

我无法让.contains 处理Candidate.bio['employment_type'],但我们可以执行与以下 SQL 等效的操作:

SELECT * FROM candidate WHERE candidate.bio @> '{"employment_type": [2]}';

像这样:

>>> employment_type = 2
>>> test = {'employment_type': [employment_type]}

>>> query = (
...     session.query(Candidate)
...     .filter(Candidate.bio.contains(test)))

>>> query.one().bio
{"employment_type": [1, 2, 3]}

【讨论】:

    猜你喜欢
    • 2015-07-04
    • 1970-01-01
    • 2021-09-28
    • 2013-09-20
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多