布尔列上的SQLAlchemy func.count

Ein*_*din 3 python postgresql sqlalchemy

如何轻松计算特定列所在的行数和特定列所在的行truefalse

我无法(或可以?)运行带有count()的查询,因为我将此计数嵌入了having()子句中,例如:

.having(func.count(Question.accepted) >
        func.count(not_(Question.accepted)))
Run Code Online (Sandbox Code Playgroud)

但是通过上述方法,该函数计算了不等式两侧的每一行。

我尝试过这样的事情

.having(func.count(func.if_(Question.accepted, 1, 0)) >
        func.count(func.if_(Question.accepted, 0, 1)))
Run Code Online (Sandbox Code Playgroud)

但我得到一个错误

函数if(布尔值,整数,整数)不存在

(似乎它在postgresql中不存在)。

如何轻松计算column为true和false的行数?

Ilj*_*ilä 5

Using aggregate functions in a HAVING clause is very much legal, since HAVING eliminates group rows. Conditional counting can be achieved either by using the property that NULLs don't count:

count(expression) ... number of input rows for which the value of expression is not null

or if using PostgreSQL 9.4 or later, with the aggregate FILTER clause:

count(*) FILTER (WHERE something > 0)
Run Code Online (Sandbox Code Playgroud)

You could also use a sum of ones (and zeros).

PostgreSQL >= 9.4 and SQLAlchemy >= 1.0.0

Using a filtered aggregate function:

.having(func.count(1).filter(Question.accepted) >
        func.count(1).filter(not_(Question.accepted)))
Run Code Online (Sandbox Code Playgroud)

Older PostgreSQL and/or SQLAlchemy

The SQL analog for "if" is either CASE expression or in this case nullif() function. Both of them can be used together with the fact that NULLs don't count:

from sqlalchemy import case

...

.having(func.count(case([(Question.accepted, 1)])) >
        func.count(case([(not_(Question.accepted), 1)])))
Run Code Online (Sandbox Code Playgroud)

or:

.having(func.count(func.nullif(Question.accepted, False)) >
        func.count(func.nullif(Question.accepted, True)))
Run Code Online (Sandbox Code Playgroud)

Using nullif() can be a bit confusing as the "condition" is what you don't want to count. You could device an expression that would make the condition more natural, but that's left for the reader. These 2 are more portable solutions, but on the other hand the FILTER clause is standard, though not widely available.