【问题标题】:Executing a sqlalchemy exists query执行 sqlalchemy 存在查询
【发布时间】:2017-11-05 17:39:40
【问题描述】:

我无法理解如何执行查询以检查 sqlalchemy 中是否已存在匹配记录。我可以在网上找到的大多数示例似乎都引用了我没有的“会话”和“查询”对象。

这是一个简短的完整程序来说明我的问题:
1. 使用“person”表建立内存sqlite db。
2.在person表中插入两条记录。
3. 检查表中是否存在特定记录。这就是它呕吐的地方。

from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData
from sqlalchemy.sql.expression import exists

engine = create_engine('sqlite:///:memory:', echo=False)
metadata = MetaData()

person = Table('person', metadata,
                        Column('id', Integer, primary_key=True),
                        Column('name', String(255), nullable=False))

metadata.create_all(engine)
conn = engine.connect()

s = person.insert()
conn.execute(s, name="Alice")
conn.execute(s, name="Bob")

print("I can see the names in the table:")
s = person.select()
result = conn.execute(s)
print(result.fetchall())

print('This query looks like it should check to see if a matching record exists:')
s = person.select().where(person.c.name == "Bob")
s = exists(s)
print(s)

print("But it doesn't run...")
result = conn.execute(s)

这个程序的输出是:

I can see the names in the table:
[(1, 'Alice'), (2, 'Bob')]
This query looks like it should check to see if a matching record exists:
EXISTS (SELECT person.id, person.name 
FROM person 
WHERE person.name = :name_1)
But it doesn't run...
Traceback (most recent call last):
  File "/project_path/db_test/db_test_env/exists_example.py", line 30, in <module>
    result = conn.execute(s)
  File "/project_path/db_test/db_test_env/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 945, in execute
    return meth(self, multiparams, params)
  File "/project_path/db_test/db_test_env/lib/python3.6/site-packages/sqlalchemy/sql/elements.py", line 265, in _execute_on_connection
    raise exc.ObjectNotExecutableError(self)
sqlalchemy.exc.ObjectNotExecutableError: Not an executable object: <sqlalchemy.sql.selectable.Exists object at 0x105797438>

【问题讨论】:

    标签: python sqlalchemy exists


    【解决方案1】:

    s.exists() 仅构建存在子句。要使代码正常工作,您需要做的就是为其生成一个选择。

    s = exists(s).select()
    

    这是您的完整示例:

    from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData
    from sqlalchemy.sql.expression import exists
    
    engine = create_engine('sqlite:///:memory:', echo=False)
    metadata = MetaData()
    
    person = Table('person', metadata,
                            Column('id', Integer, primary_key=True),
                            Column('name', String(255), nullable=False))
    
    metadata.create_all(engine)
    conn = engine.connect()
    
    s = person.insert()
    conn.execute(s, name="Alice")
    conn.execute(s, name="Bob")
    
    print("I can see the names in the table:")
    s = person.select()
    result = conn.execute(s)
    print(result.fetchall())
    
    print('This query looks like it should check to see if a matching record exists:')
    s = person.select().where(person.c.name == "Bob")
    s = exists(s).select()
    print(s)
    
    print("And it runs fine...")
    result = conn.execute(s)
    print(result.fetchall())
    

    【讨论】:

    • 谢谢!这正是我想要的!我是如此接近,我只是不知道如何包装额外的选择。谢谢你。我可能会做的唯一小改动是:result = conn.execute(s).scalar() 所以我们只取回基本的 True / False 而不是结果行。
    【解决方案2】:

    exists 用于 SQL 子查询。如果您有一个表 posts 包含带有 author_id 的博客文章,并映射回人员,您可以使用如下查询来查找发表博客文章的人:

    select * from people where exists (select author_id from posts where author_id = people.id);
    

    您不能将存在作为 SQL 查询中的最外层语句;它是在 SQL 布尔子句中使用的运算符。 因此,SQLAlchemy 不允许您执行该查询,因为它的格式不正确。 如果要查看一行是否存在,只需构造一个带有 where 子句的 select 语句,然后查看查询返回了多少行。

    【讨论】:

    • 谢谢,Sam,但我认为必须有更好的方法。我不想从数据库中传输可能有很多匹配的行,我只想传输真或假标量值。
    • 在您的查询中添加limit 1。这就是我看到很多网络应用程序所做的事情。
    【解决方案3】:

    试试这个:

    ...
    s = person.select().where(person.c.name == "Bob")
    s = select(exists(s))
    print(s)
    ...
    

    【讨论】:

      【解决方案4】:

      除非有人提出更好的答案,否则这就是我想出的有效方法。让数据库计算匹配记录并将计数发送到 python 应用程序。

      from sqlalchemy import select, func   # more imports not in my example code above
      
      s = select([func.count(1)]).select_from(person).where(person.c.name == "Bob")
      print(s)
      record_count = conn.execute(s).scalar()
      print("Matching records: ", record_count)
      

      示例输出:

      SELECT count(:count_2) AS count_1 
      FROM person 
      WHERE person.name = :name_1
      Matching records:  1
      

      【讨论】:

        猜你喜欢
        • 2015-07-22
        • 2017-05-13
        • 1970-01-01
        • 1970-01-01
        • 2021-03-09
        • 2018-01-16
        • 2017-04-04
        • 1970-01-01
        • 2018-09-08
        相关资源
        最近更新 更多