- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个 Postgres 查询(通过 SQLAlchemy),它使用复杂的条件选择匹配的行:
original_query = session.query(SomeTable).filter(*complex_filters)
我不知道查询是如何构造的,我只能访问生成的查询实例。
现在我想使用这个“不透明”查询(出于这个问题的目的是黑盒)来构造其他查询,从同一个表使用完全相同的标准,但在匹配的 original_query
行之上有额外的逻辑.例如,顶部为 SELECT DISTINCT(column)
:
another_query = session.query(SomeTable.column).distinct().?select_from_query?(original_query)
或
SELECT SUM(tab_value) FROM (
SELECT tab.key AS tab_key, tab.value AS tab_value -- inner query, fixed
FROM tab
WHERE tab.product_id IN (1, 2) -- simplified; the inner query is quite complex
) AS tbl
WHERE tab_key = 'length';
或
SELECT tab_key, COUNT(*) FROM (
SELECT tab.key AS tab_key, tab.value AS tab_value
FROM tab
WHERE tab.product_id IN (1, 2)
) AS tbl
GROUP BY tab_key;
等等
如何在 SQLAlchemy 中干净地实现 ?select_from_query?
部分?基本上,如何在 SqlAlchemy 中执行 SELECT dynamic FROM (SELECT fixed)
?
动机:内部 Query 对象来自代码的不同部分。我无法控制它的构造方式,并且希望避免为我必须在其上运行的每个 SELECT
重复其逻辑。我想重新使用该查询,但在顶部添加额外的逻辑(按照上面的示例)。
最佳答案
original_query
只是一个SQLAlchemy query API object ,您可以对此应用其他过滤器和条件。查询 API 是生成的;每个Query()
实例操作返回一个新的(不可变的)实例并且您的起点(original_query
)不受影响。
这包括使用 Query.distinct()
添加 DISTINCT()
条款, Query.with_entities()
更改哪些列是查询的一部分,以及 Query.values()
执行查询但仅返回特定的单列值。
使用 .distinct(<column>).with_entities(<column>)
创建一个新的查询对象(可以进一步重复使用):
another_query = original_query.distinct(SomeTable.column).with_entities(SomeTable.column)
或者只使用 .distinct(<column>).values(<column>)
得到 (column_value,)
的迭代器元组结果就在那里然后:
distinct_values = original_query.distinct(SomeTable.column).values(SomeTable.column)
请注意 .values()
立即执行查询,如 .all()
会,而.with_entities()
还给你一个新的 Query
只有单列的对象(然后将执行 .all()
或迭代或切片并返回结果)。
演示,使用人为的 Foo
模型(针对 sqlite 执行以使其更容易快速演示):
>>> from sqlalchemy import *
>>> from sqlalchemy.ext.declarative import declarative_base
>>> from sqlalchemy.orm import sessionmaker
>>> Base = declarative_base()
>>> class Foo(Base):
... __tablename__ = "foo"
... id = Column(Integer, primary_key=True)
... bar = Column(String)
... spam = Column(String)
...
>>> engine = create_engine('sqlite:///:memory:', echo=True)
>>> session = sessionmaker(bind=engine)()
>>> Base.metadata.create_all(engine)
2019-06-10 13:10:43,910 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("foo")
2019-06-10 13:10:43,910 INFO sqlalchemy.engine.base.Engine ()
2019-06-10 13:10:43,911 INFO sqlalchemy.engine.base.Engine
CREATE TABLE foo (
id INTEGER NOT NULL,
bar VARCHAR,
spam VARCHAR,
PRIMARY KEY (id)
)
2019-06-10 13:10:43,911 INFO sqlalchemy.engine.base.Engine ()
2019-06-10 13:10:43,913 INFO sqlalchemy.engine.base.Engine COMMIT
>>> original_query = session.query(Foo).filter(Foo.id.between(17, 42))
>>> print(original_query) # show what SQL would be executed for this query
SELECT foo.id AS foo_id, foo.bar AS foo_bar, foo.spam AS foo_spam
FROM foo
WHERE foo.id BETWEEN ? AND ?
>>> another_query = original_query.distinct(Foo.bar).with_entities(Foo.bar)
>>> print(another_query) # print the SQL again, don't execute
SELECT DISTINCT foo.bar AS foo_bar
FROM foo
WHERE foo.id BETWEEN ? AND ?
>>> distinct_values = original_query.distinct(Foo.bar).values(Foo.bar) # executes!
2019-06-10 13:10:48,470 INFO sqlalchemy.engine.base.Engine SELECT DISTINCT foo.bar AS foo_bar
FROM foo
WHERE foo.id BETWEEN ? AND ?
2019-06-10 13:10:48,470 INFO sqlalchemy.engine.base.Engine (17, 42)
在上面的演示中,原始查询将选择某些 Foo
带有 BETWEEN
的实例过滤器,但添加 .distinct(Foo.bar).values(Foo.bar)
然后对 just DISTINCT foo.bar
执行查询列,但具有相同的 BETWEEN
过滤到位。同样,通过使用 .with_entities()
,我们只为该单列提供了一个新的查询对象,但过滤器仍然是该新查询的一部分。
您添加的示例的工作方式相同;您实际上不需要在那里进行子选择,因为相同的查询可以表示为:
SELECT sum(tab.value)
FROM tab
WHERE tab.product_id IN (1, 2) AND tab_key = 'length';
这可以简单地通过添加额外的过滤器然后使用 .with_entities()
来实现。用您的 SUM()
替换所选的列:
summed_query = (
original_query
.filter(Tab.key == 'length') # add a filter
.with_entities(func.sum(Tab.value)
或者,根据上述Foo
演示:
>>> print(original_query.filter(Foo.spam == 42).with_entities(func.sum(Foo.bar)))
SELECT sum(foo.bar) AS sum_1
FROM foo
WHERE foo.id BETWEEN ? AND ? AND foo.spam = ?
有子查询的用例(例如限制连接中特定表的结果),但这不是其中之一。
如果你确实需要一个子查询,那么查询 API 有 Query.from_self()
(对于更简单的情况)和 Query.subselect()
.
例如,如果您只需要从原始查询中选择聚合行并通过 HAVING
过滤聚合值, 然后将结果与另一个表连接起来,以获得每个组的最高行 ID 和一些进一步的过滤,然后你需要一个子查询:
summed_col = func.sum(SomeTable.some_column)
max_id = func.max(SomeTable.primary_key)
summed_results_by_eggs = (
original_query
.with_entities(max_id, summed_col) # only select highest id and the sum
.group_by(SomeTable.other_column) # per group
.having(summed_col > 10) # where the sum is high enough
.from_self(summed_col) # give us the summed value as a subselect
.join( # join these rows with another table
OtherTable,
OtherTable.foreign_key == max_id # using the highest id
)
.filter(OtherTable.some_column < 1000) # and filter some more
)
上面只会选择求和的SomeTable.some_column
该值大于 10 且最高 SomeTable.id
的值每个组中的值。此查询必须使用子查询,因为您要限制符合条件的 SomeTable
加入另一个表之前的行。
为了演示这个,我添加了第二个表 Eggs
:
>>> from sqlalchemy.orm import relationship
>>> class Eggs(Base):
... __tablename__ = "eggs"
... id = Column(Integer, primary_key=True)
... foo_id = Column(Integer, ForeignKey(Foo.id))
... foo = relationship(Foo, backref="eggs")
...
>>> summed_col = func.sum(Foo.bar)
>>> max_id = func.max(Foo.id)
>>> print(
... original_query
... .with_entities(max_id, summed_col)
... .group_by(Foo.spam)
... .having(summed_col > 10)
... .from_self(summed_col)
... .join(Eggs, Eggs.foo_id==max_id)
... .filter(Eggs.id < 1000)
... )
SELECT anon_1.sum_2 AS sum_1
FROM (SELECT max(foo.id) AS max_1, sum(foo.bar) AS sum_2
FROM foo
WHERE foo.id BETWEEN ? AND ? GROUP BY foo.spam
HAVING sum(foo.bar) > ?) AS anon_1 JOIN eggs ON eggs.foo_id = anon_1.max_1
WHERE eggs.id < ?
Query.from_self()
方法采用新实体在外部查询中使用,如果您省略这些实体,则所有列都将被拉出。在上面,我提取了汇总的列值;没有那个论点MAX(Foo.id)
列也将被选中。
关于python - 如何在 SqlAlchemy 中进行不带 JOIN 的嵌套 SELECT?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56525884/
我正在处理一组标记为 160 个组的 173k 点。我想通过合并最接近的(到 9 或 10 个组)来减少组/集群的数量。我搜索过 sklearn 或类似的库,但没有成功。 我猜它只是通过 knn 聚类
我有一个扁平数字列表,这些数字逻辑上以 3 为一组,其中每个三元组是 (number, __ignored, flag[0 or 1]),例如: [7,56,1, 8,0,0, 2,0,0, 6,1,
我正在使用 pipenv 来管理我的包。我想编写一个 python 脚本来调用另一个使用不同虚拟环境(VE)的 python 脚本。 如何运行使用 VE1 的 python 脚本 1 并调用另一个 p
假设我有一个文件 script.py 位于 path = "foo/bar/script.py"。我正在寻找一种在 Python 中通过函数 execute_script() 从我的主要 Python
这听起来像是谜语或笑话,但实际上我还没有找到这个问题的答案。 问题到底是什么? 我想运行 2 个脚本。在第一个脚本中,我调用另一个脚本,但我希望它们继续并行,而不是在两个单独的线程中。主要是我不希望第
我有一个带有 python 2.5.5 的软件。我想发送一个命令,该命令将在 python 2.7.5 中启动一个脚本,然后继续执行该脚本。 我试过用 #!python2.7.5 和http://re
我在 python 命令行(使用 python 2.7)中,并尝试运行 Python 脚本。我的操作系统是 Windows 7。我已将我的目录设置为包含我所有脚本的文件夹,使用: os.chdir("
剧透:部分解决(见最后)。 以下是使用 Python 嵌入的代码示例: #include int main(int argc, char** argv) { Py_SetPythonHome
假设我有以下列表,对应于及时的股票价格: prices = [1, 3, 7, 10, 9, 8, 5, 3, 6, 8, 12, 9, 6, 10, 13, 8, 4, 11] 我想确定以下总体上最
所以我试图在选择某个单选按钮时更改此框架的背景。 我的框架位于一个类中,并且单选按钮的功能位于该类之外。 (这样我就可以在所有其他框架上调用它们。) 问题是每当我选择单选按钮时都会出现以下错误: co
我正在尝试将字符串与 python 中的正则表达式进行比较,如下所示, #!/usr/bin/env python3 import re str1 = "Expecting property name
考虑以下原型(prototype) Boost.Python 模块,该模块从单独的 C++ 头文件中引入类“D”。 /* file: a/b.cpp */ BOOST_PYTHON_MODULE(c)
如何编写一个程序来“识别函数调用的行号?” python 检查模块提供了定位行号的选项,但是, def di(): return inspect.currentframe().f_back.f_l
我已经使用 macports 安装了 Python 2.7,并且由于我的 $PATH 变量,这就是我输入 $ python 时得到的变量。然而,virtualenv 默认使用 Python 2.6,除
我只想问如何加快 python 上的 re.search 速度。 我有一个很长的字符串行,长度为 176861(即带有一些符号的字母数字字符),我使用此函数测试了该行以进行研究: def getExe
list1= [u'%app%%General%%Council%', u'%people%', u'%people%%Regional%%Council%%Mandate%', u'%ppp%%Ge
这个问题在这里已经有了答案: Is it Pythonic to use list comprehensions for just side effects? (7 个答案) 关闭 4 个月前。 告
我想用 Python 将两个列表组合成一个列表,方法如下: a = [1,1,1,2,2,2,3,3,3,3] b= ["Sun", "is", "bright", "June","and" ,"Ju
我正在运行带有最新 Boost 发行版 (1.55.0) 的 Mac OS X 10.8.4 (Darwin 12.4.0)。我正在按照说明 here构建包含在我的发行版中的教程 Boost-Pyth
学习 Python,我正在尝试制作一个没有任何第 3 方库的网络抓取工具,这样过程对我来说并没有简化,而且我知道我在做什么。我浏览了一些在线资源,但所有这些都让我对某些事情感到困惑。 html 看起来
我是一名优秀的程序员,十分优秀!