使用 Postgres 和 SQLAlchemy 过滤数组列

Posted

技术标签:

【中文标题】使用 Postgres 和 SQLAlchemy 过滤数组列【英文标题】:Filter with Array column with Postgres and SQLAlchemy 【发布时间】:2014-06-25 23:24:51 【问题描述】:

我有一个带有 int[] 列的简单表,我希望能够选择其中任何一个数组元素与我拥有的值匹配的行,但我无法弄清楚如何使用 SQLAlchemy 来做到这一点不只使用原始查询,我不想这样做。

这是表(“testuser”)的架构:

 Column  |          Type          |
---------+------------------------+
 id      | integer                |
 name    | character varying(250) |
 numbers | integer[]              |

下面是示例数据:

 id |  name   |    numbers
----+---------+---------------
  1 | David   | 25,33,42,55
  2 | Salazar | 11,33,7,19
  3 | Belinda | 32,6,20,23
  4 | Casey   | 19,20,27,8
  5 | Kathie  | 25,31,10,40
  6 | Dianne  | 25,20,40,39
  7 | Cortez  | 1,20,18,38

这是一个生成我想要的 SQL 语句;我想在 Python 中完成这一切,而不是简单地编写原始查询(25 仅用作示例)。

scrape=# select * from testuser where 25 = ANY(numbers);
 id |  name  |    numbers
----+--------+---------------
  5 | Kathie | 25,31,10,40
  6 | Dianne | 25,20,40,39
  1 | David  | 25,33,42,55
(3 rows)

我发现的另一种写法:

scrape=# select * from testuser where numbers @> ARRAY[25];
 id |  name  |    numbers
----+--------+---------------
  5 | Kathie | 25,31,10,40
  6 | Dianne | 25,20,40,39
  1 | David  | 25,33,42,55
(3 rows)

这是我用来生成表格的 Python 代码:

from sqlalchemy import Column, Integer, String
from sqlalchemy.dialects import postgresql
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

Base = declarative_base()

class TestUser(Base):
    __tablename__ = 'testuser'
    id = Column(Integer, primary_key=True)
    name = Column(String(250))
    numbers = Column(postgresql.ARRAY(Integer))

engine = create_engine('postgresql://postgres:pw@localhost:5432/scrape'.format(pw=POSTGRES_PASSWORD))

Base.metadata.create_all(engine)

DBSession = sessionmaker(bind=engine)
session = DBSession()

testcases = ["numbers": [25, 33, 42, 55], "name": "David", "numbers": [11, 33, 7, 19 ], "name":     "Salazar", "numbers": [32, 6, 20, 23 ], "name": "Belinda", "numbers": [19, 20, 27, 8 ], "name": "Casey",     "numbers": [25, 31, 10, 40 ], "name": "Kathie", "numbers": [25, 20, 40, 39 ], "name": "Dianne",     "numbers": [1, 20, 18, 38 ], "name": "Cortez" ]

for t in testcases:
    session.add(TestUser(name=t['name'], numbers=t['numbers']))
session.commit()

【问题讨论】:

【参考方案1】:

所以你想使用 Postgres Array Comparator。

query = session.query(TestUser).filter(TestUser.numbers.contains([some_int])).all()

query = session.query(TestUser).filter(TestUser.numbers.any(25)).all()

【讨论】:

出现错误,但您指出了正确的方向。需要是 [some_int] (包含需要与数组进行比较)或 any(some_int) -- session.query(TestUser).filter(TestUser.numbers.any(25)).all() -- 谢谢! 使用 ARRAY(db.String) 代替 db.Integer 会出现问题,需要进行强制转换 TestUser.numbers.contains(cast([some_int], ARRAY(String))) 【参考方案2】:

该死的 SQLAlchemy,我花了一些时间才弄清楚正确的方法是:

TelegramUser.query.filter(TelegramUser.selected_exchanges.contains(f"platform_name")).all()

其中platform_namestrselected_exchanges 列定义如下:

from sqlalchemy.dialects import postgresql as pg

selected_exchanges = db.Column(pg.ARRAY(db.String, dimensions=1), nullable=True)

【讨论】:

正确的方法是在接受的答案中。手动形成 SQL 容易出错且不必要。 contains([platform_name]) 会工作并且更安全。

以上是关于使用 Postgres 和 SQLAlchemy 过滤数组列的主要内容,如果未能解决你的问题,请参考以下文章

我从 sqlalchemy 得到一个“幽灵”回滚,但在使用 psql 和 postgres 时没有

使用 Sqlalchemy 连接和 Postgres 从原始字符串编译查询(不使用 .text(...))

Postgres 模式的 SQLAlchemy 支持

uWSGI、Flask、sqlalchemy 和 postgres:SSL 错误:解密失败或坏记录 mac

如何使用 Postgres 在 SQLAlchemy 中创建表?

如何使用 SQLAlchemy Postgres ORM 的声明性基础动态创建具有列名和字典约束的表?