SQL炼金术筛选功能计数查询内

2024-06-17 14:51:03 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有一个表,其中有一个列,它有一些整数值,我想计算该列超过200的值所占的百分比。在

这是一个关键问题,我希望我可以在一个查询内完成,我可以使用groupbyon。在

results = db.session.query(
        ClassA.some_variable,
        label('entries', func.count(ClassA.some_variable)),
        label('percent', *no clue*)
  ).filter(ClassA.value.isnot(None)).group_by(ClassA.some_variable)

或者,如果不喜欢在客户端进行百分比计算,也可以这样做。在

^{pr2}$

但是我显然不能在count statemenet中进行筛选,也不能在查询的末尾应用筛选器,因为如果在结尾应用>;200约束,total_count将无法工作。在

使用原始SQL也是一种选择,它不必是Sqlalchemy


Tags: dbsessioncount整数somequeryvariableresults
1条回答
网友
1楼 · 发布于 2024-06-17 14:51:03

不幸的是,MariaDB不支持aggregate FILTER clause,但您可以解决using a CASE expression或{a3},因为COUNT返回给定表达式的非空值计数:

from sqlalchemy import case

...

func.count(case([(ClassA.value > 200, 1)])).label('over_200_count')

考虑到这一点,你可以简单地计算百分比

^{pr2}$

尽管有一个边缘:如果func.count(ClassA.value)is 0怎么办?根据您将0还是NULL视为有效返回值,您可以使用另一个CASE表达式或NULLIF:

dividend = func.count(case([(ClassA.value > 200, 1)])) * 1.0
divisor = func.count(ClassA.value)

# Zero
case([(divisor == 0, 0)],
     else_=dividend / divisor).label('percent')

# NULL
(dividend / func.nullif(divisor, 0)).label('percent')

最后,您可以为mysql方言创建一个compilation extension,它将过滤器子句重写为合适的CASE表达式:

from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import FunctionFilter
from sqlalchemy.sql.functions import Function
from sqlalchemy import case


@compiles(FunctionFilter, 'mysql')
def compile_functionfilter_mysql(element, compiler, **kwgs):
    # Support unary functions only
    arg0, = element.func.clauses

    new_func = Function(
        element.func.name,
        case([(element.criterion, arg0)]),
        packagenames=element.func.packagenames,
        type_=element.func.type,
        bind=element.func._bind)

    return new_func._compiler_dispatch(compiler, **kwgs)

有了这些,你可以把股息表达为

dividend = func.count(1).filter(ClassA.value > 200) * 1.0

编译成

In [28]: print(dividend.compile(dialect=mysql.dialect()))
count(CASE WHEN (class_a.value > %s) THEN %s END) * %s

相关问题 更多 >