Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/362.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使用SQLAlchemy获取与3元组条件列表匹配的行_Python_Sql_Sqlalchemy - Fatal编程技术网

Python 如何使用SQLAlchemy获取与3元组条件列表匹配的行

Python 如何使用SQLAlchemy获取与3元组条件列表匹配的行,python,sql,sqlalchemy,Python,Sql,Sqlalchemy,具有3元组列表: [(a, b, c), (d, e, f)] 我想从3列匹配元组的表中检索所有行。对于本例,查询WHERE子句可以是这样的: (column_X = a AND column_Y = b AND column_Z = c) OR (column_X = d AND column_Y = e AND column_Z = f) 如何使用SQLAlchemy创建这样的请求?在我的例子中,3元组列表将包含数百个元素,我正在寻找最好的可伸缩解决方案 感谢您的帮助,最简单的方法

具有3元组列表:

[(a, b, c), (d, e, f)]
我想从3列匹配元组的表中检索所有行。对于本例,查询
WHERE
子句可以是这样的:

   (column_X = a AND column_Y = b AND column_Z = c)
OR (column_X = d AND column_Y = e AND column_Z = f)
如何使用SQLAlchemy创建这样的请求?在我的例子中,3元组列表将包含数百个元素,我正在寻找最好的可伸缩解决方案


感谢您的帮助,

最简单的方法是使用SQLAlchemy提供的函数:

from sqlalchemy import tuple_

session.query(Foo).filter(tuple_(Foo.a, Foo.b, Foo.c).in_(items))
这适用于PostgreSQL,但不适用于SQLite。不确定其他数据库引擎

幸运的是,有一个解决方案可以在所有数据库上使用

首先用
表达式映射出所有项目:

conditions = (and_(c1=x, c2=y, c3=z) for (x, y, z) in items)
然后创建一个包含所有条件的
过滤器:

q.filter(or_(*conditions))
下面是一个简单的例子:

#/usr/bin/env python
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer
from sqlalchemy.sql import and_, or_
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///')
session = sessionmaker(bind=engine)()
Base = declarative_base()

class Foo(Base):
    __tablename__ = 'foo'

    id = Column(Integer, primary_key=True)
    a = Column(Integer)
    b = Column(Integer)
    c = Column(Integer)

    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

    def __repr__(self):
        return '(%d %d %d)' % (self.a, self.b, self.c)

Base.metadata.create_all(engine)

session.add_all([Foo(1, 2, 3), Foo(3, 2, 1), Foo(3, 3, 3), Foo(1, 3, 4)])
session.commit()
items = ((1, 2, 3), (3, 3, 3))
conditions = (and_(Foo.a==x, Foo.b==y, Foo.c==z) for (x, y, z) in items)
q = session.query(Foo)
print q.all()
q = q.filter(or_(*conditions))
print q
print q.all()
哪些产出:

$ python test.py 
[(1 2 3), (3 2 1), (3 3 3), (1 3 4)]
SELECT foo.id AS foo_id, foo.a AS foo_a, foo.b AS foo_b, foo.c AS foo_c 
FROM foo 
WHERE foo.a = :a_1 AND foo.b = :b_1 AND foo.c = :c_1 OR foo.a = :a_2 AND foo.b = :b_2 AND foo.c = :c_2
[(1 2 3), (3 3 3)]

我认为一种不太传统的方法可以很好地扩展,那就是创建一个包含所有元组的临时表,然后在此基础上进行连接:

import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, Table
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
engine = sqlalchemy.create_engine('sqlite:///:memory:')
Session = sessionmaker(bind=engine)
session = Session()

class Triple(Base):
    __tablename__ = 'triple'
    id = Column(Integer(), primary_key=True)
    x = Column(Integer())
    y = Column(Integer())
    z = Column(Integer())

ws_table = Table('where_sets', Base.metadata,
        Column('x', Integer()),
        Column('y', Integer()),
        Column('z', Integer()),
        prefixes = ['temporary']
    )

Base.metadata.create_all(engine)

...

where_sets = [(1, 2, 3), (3, 2, 1), (1, 1, 1)]
ws_table.create(engine, checkfirst=True)
session.execute(ws_table.insert(), [dict(zip('xyz', s)) for s in where_sets])
matches = session.query(Triple).join(ws_table, (Triple.x==ws_table.c.x) & (Triple.y==ws_table.c.y) & (Triple.z==ws_table.c.z)).all()
它执行SQL的方式如下:

INSERT INTO triple (x, y, z) VALUES (?, ?, ?)
(1, 2, 3)
INSERT INTO triple (x, y, z) VALUES (?, ?, ?)
(3, 1, 2)
INSERT INTO triple (x, y, z) VALUES (?, ?, ?)
(1, 1, 1)
SELECT triple.id AS triple_id, triple.x AS triple_x, triple.y AS triple_y, triple.z AS triple_z 
FROM triple JOIN where_sets ON triple.x = where_sets.x AND triple.y = where_sets.y AND triple.z = where_sets.z

有人会考虑在原始表中创建一个额外的密钥吗?
i、 e.用“1”-“2”-“3”代替另一个表创建一个新列,并检查其唯一性

非常感谢,太完美了!我想这个解决方案可能比前一个慢得多,你不觉得吗?无论如何,谢谢你的例子:-)@Thibaut:在你尝试之前不会知道的!我所知道的是,我已经用巨大的“IN”条款让高规模生产系统屈服,我不知道巨大的“WHERE”条款在原则上会更好。但是你知道很多插入和一个小的连接就可以了。因为你特别要求的是“最佳可扩展解决方案”,这正是我的想法,但也许几百个还不够,这无论如何都很重要。无论如何,如果你需要的话,它就在那里。我不会测试bc,我会在小规模上使用它,但它看起来比巨大的and和OR以及WHERE和INs更具可伸缩性。插入和连接通常非常快,除非插入大量od数据。我的意思是添加索引