【问题标题】:In SQLAlchemy, how do I query composite primary keys?在 SQLAlchemy 中,如何查询复合主键?
【发布时间】:2016-03-23 01:45:21
【问题描述】:

我正在使用 SQLAlchemy 以编程方式查询具有复合外键的表。例如:

CREATE TABLE example (
id INT NOT NULL,
date TIMESTAMP NOT NULL,
data VARCHAR(128)
PRIMARY KEY (id, date)
)

我想获取一个值列表并取回行,例如:

interesting_data = (
    (1, '2016-5-1'), 
    (1, '2016-6-1'),
    (2, '2016-6-1'),
    (3, '2016-5-1'),
    (3, '2016-6-1'),
)
select(
    [example.c.id, example.c.date, example.c.data],
).where(example.primary_key.in_(interesting_data)

如果每一列都是独立的,我可以这样做

interesting_ids = [1,2,3]
interesting_dates = ['2016-5-1', '2016-6-1']
select(
    [example.c.id, example.c.date, example.c.data],
).where(
    example.c.id.in_(interesting_ids)
).where(
    example.c.date.in_(interesting_dates)
)

但这显然不能只带来唯一匹配的 (id, date) 元组。我怀疑有一种方法可以指定要查询的复合主键,但搜索后我找不到任何文档。

【问题讨论】:

    标签: python sql sqlalchemy compound-key


    【解决方案1】:

    假设您的模型类名为Example,其中 (id, date) 是复合主键:

    您可以通过以下方式查询:

    import sqlalchemy
    ...
    Example.query.get((id, date))
    

    import sqlalchemy
    from sqlalchemy.orm import sessionmaker
    ...
    engine = sqlalchemy.create_engine('postgresql://user:pass@localhost/db_name')
    session = sessionmaker(bind=engine)()
    session.query(Example).get((id, date))
    

    【讨论】:

      【解决方案2】:

      在 where 子句中使用列表推导:

      from sqlalchemy import and_, or_, select
      
      stmt = select(
          [example.c.id, example.c.date, example.c.data]
      ).where(or_(and_(example.c.id==data[0], example.c.date==data[1])
                  for data in interesting_data))
      

      但是,我注意到的另一个问题是您将日期列与字符串数据类型进行比较。 interesting_data 列表应该是

      import datetime as dt
      
      interesting_data = (
          (1, dt.date(2016,5,1)), 
          (1, dt.date(2016,6,1)),
          (2, dt.date(2016,6,1)),
          (3, dt.date(2016,6,1)),
          (3, dt.date(2016,6,1)),
      )
      

      另外,请注意,可以创建一个基本语句,然后逐步向其中添加子句,从而(希望)带来更好的易读性和代码重用。

      所以,上面可以写成

      base_stmt = select([example.c.id, example.c.date, example.c.data])
      wheres = or_(and_(example.c.id==data[0], example.c.date==data[1])
                   for data in interesting_data))
      stmt = base_stmt.where(wheres)
      

      这会生成以下 sql(我添加的换行符和空格):

      SELECT example.id, example.date, example.data 
      FROM example 
      WHERE 
         example.id = :id_1 AND example.date = :date_1 
      OR example.id = :id_2 AND example.date = :date_2
      OR example.id = :id_3 AND example.date = :date_3 
      OR example.id = :id_4 AND example.date = :date_4 
      OR example.id = :id_5 AND example.date = :date_5
      

      注意:如果你有很多行要像这样过滤,创建一个临时表,从interesting_data向这个临时表中插入行,然后进行内连接可能会更有效到这个表中,而不是像上面显示的那样添加 where 子句。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-06
        • 1970-01-01
        • 2020-09-29
        • 1970-01-01
        • 1970-01-01
        • 2018-08-01
        相关资源
        最近更新 更多