我想检索查询的所有结果。我的代码如下:
engine = sqlalchemy.create_engine(...)
Base = declarative_base()
class Something(Base):
...
Session = sessionmaker(bind=engine)
session = Session()
query = session.query(Something).filter(...).all()
我看到query.count() == 3000
,但当我尝试results = query.all()
时,我只获得一行(即len(results) == 1
)。
我的理解是query.all()
执行查询并返回所有结果的列表。我在这里错过了什么吗?计算的行数大于返回的行数有哪些可能的原因?
修改(更多细节):
采用原始SQL(例如查看str(query)
并进行参数替换)并将其传递到session.execute
似乎工作正常:
# this gives 3000 rows
for row in session.execute(raw_sql, {'param1': val1, 'param2': val2}):
print(row)
解决方案
原来问题是我的主键不是唯一的。获得的经验:在上课时要非常小心!就我而言,我有:
class Something(Base):
row_id_1 = Column(Integer, primary_key=True)
row_id_2 = Column(Integer) # PROBLEM! Need to specify primary_key=True
value = Column(Float)
这会导致问题,因为主键是组合(row_id_1,row_id_2)。
答案 0 :(得分:1)
您的问题与您的主键不唯一有关。假设您的映射是......
class Something(Base):
__tablename__ = 'things'
id = Column(Integer, primary_key=True)
name = Column(String(50))
您的数据库中包含以下数据......
| ID| Name |
| 1 | Larry |
| 1 | Moe |
| 1 | Curly |
如果你......
SELECT * FROM names
你会得到三个结果。这就是SQLAlchemy中的execute
函数。
然而,ORM超越了一步。使用ORM查询“事物”表时,结果将变为Something
个对象。此外,他们使用Identity Map跟踪SQLAlchemy。在将第一个记录(“Larry”)转换为对象后,它会查看第二个记录(“Moe”,也是ID为1)。由于ID为1完全相同,因此它假定记录表示与第一个记录相同的对象。因此,它不会实例化新的Something
对象,只会转到下一条记录。
来自the docs:
在最一般意义上,会话建立与数据库的所有对话,并代表您在其生命周期内加载或与之关联的所有对象的“保留区域”。它提供了获取Query对象的入口点,Query对象使用Session对象的当前数据库连接将查询发送到数据库,将结果行填充到随后存储在Session中的对象中,称为Identity Map的结构 - 维护的数据结构每个对象的唯一副本,其中“唯一”表示“只有一个具有特定主键的对象”。
“身份地图”是您看到此行为的原因。当您说主键是“ID”字段时,SQLAlchemy会将您带到此承诺,如果它看到返回的多个记录具有相同的ID,则它会认为它们都是同一个对象。
确保您的主键是唯一的是解决方案。