从表中的不同条件中选择COUNT
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从表中的不同条件中选择COUNT相关的知识,希望对你有一定的参考价值。
我有一张名为'jobs'的桌子。对于特定用户,作业可以是活动的,存档的,过期的,挂起的或关闭的。现在每个页面请求都生成5个COUNT个查询,并且在尝试优化时我试图将其减少为单个查询。这是我到目前为止所拥有的,但它几乎比5个单独的查询快。请注意,我已经简化了每个子查询的条件,使其更容易理解,但完整查询的行为却相同。
有没有办法在不使用低效子查询的情况下在同一查询中获取这5个计数?
SELECT
(SELECT count(*)
FROM "jobs"
WHERE
jobs.creator_id = 5 AND
jobs.status_id NOT IN (8,3,11) /* 8,3,11 being 'inactive' related statuses */
) AS active_count,
(SELECT count(*)
FROM "jobs"
WHERE
jobs.creator_id = 5 AND
jobs.due_date < '2011-06-14' AND
jobs.status_id NOT IN(8,11,5,3) /* Grabs the overdue active jobs
('5' means completed successfully) */
) AS overdue_count,
(SELECT count(*)
FROM "jobs"
WHERE
jobs.creator_id = 5 AND
jobs.due_date BETWEEN '2011-06-14' AND '2011-06-15 06:00:00.000000'
) AS due_today_count
这继续2个子查询,但我想你明白了。
是否有更简单的方法来收集这些数据,因为它基本上是5个不同的COUNT,来自作业表的相同数据子集?
数据子集是'creator_id = 5',之后每个计数基本上只有1-2个附加条件。请注意,目前我们正在使用Postgres,但可能会在不久的将来转向mysql。因此,如果您能提供与ANSI兼容的解决方案,我将非常感激:)
这是典型的解决方案。使用案例陈述来突破不同的条件。如果记录符合它,则得到1,否则为0.然后对值进行SUM
SELECT
SUM(active_count) active_count,
SUM(overdue_count) overdue_count
SUM(due_today_count) due_today_count
FROM
(
SELECT
CASE WHEN jobs.status_id NOT IN (8,3,11) THEN 1 ELSE 0 END active_count,
CASE WHEN jobs.due_date < '2011-06-14' AND jobs.status_id NOT IN(8,11,5,3) THEN 1 ELSE 0 END overdue_count,
CASE WHEN jobs.due_date BETWEEN '2011-06-14' AND '2011-06-15 06:00:00.000000' THEN 1 ELSE 0 END due_today_count
FROM "jobs"
WHERE
jobs.creator_id = 5 ) t
更新如前所述,当0记录返回为t时,这导致所有值中的Null的单个结果。你有三个选择
1)添加A Having子句,以便您没有返回记录而不是所有NULLS的结果
HAVING SUM(active_count) is not null
2)如果你想要返回所有零,那么你可以为你的所有总和添加合并
例如
SELECT
COALESCE(SUM(active_count)) active_count,
COALESCE(SUM(overdue_count)) overdue_count
COALESCE(SUM(due_today_count)) due_today_count
3)利用COUNT(NULL) = 0
作为sbarro演示的事实。您应该注意,not-null值可以是不必为1的任何值
例如
SELECT
COUNT(CASE WHEN
jobs.status_id NOT IN (8,3,11) THEN 'Manticores Rock' ELSE NULL
END) as [active_count]
我会使用这种方法,将COUNT与CASE WHEN结合使用。
SELECT
COUNT(CASE WHEN
jobs.status_id NOT IN (8,3,11) THEN 1
END) as [Count1],
COUNT(CASE WHEN
jobs.due_date < '2011-06-14'
AND jobs.status_id NOT IN(8,11,5,3) THEN 1
END) as [COUNT2],
COUNT(CASE WHEN
jobs.due_date BETWEEN '2011-06-14' AND '2011-06-15 06:00:00.000000'
END) as [COUNT3]
FROM
"jobs"
WHERE
jobs.creator_id = 5
简要
SQL Server 2012 introduced the IIF
logical function。使用SQL Server 2012或更高版本,您现在可以使用此新函数而不是CASE
表达式。 IIF
函数也适用于Azure SQL数据库(但目前它不适用于Azure SQL数据仓库或并行数据仓库)。它是CASE
表达的简写。
当只有一个案例时,我发现自己使用IIF
函数而不是CASE
表达式。这减轻了必须写CASE WHEN condition THEN x ELSE y END
而不是写为IIF(condition, x, y)
的痛苦。如果可以满足多个条件(多个WHEN
s),则应考虑使用常规CASE
表达式而不是嵌套的IIF
函数。
返回两个值中的一个,具体取决于布尔表达式在SQL Server中的计算结果为true还是false。
句法
IIF ( boolean_expression, true_value, false_value )
参数
boolean_expression
有效的布尔表达式。如果此参数不是布尔表达式,则会引发语法错误。
true_value
如果boolean_expression
评估为真,则返回值。
false_value
如果boolean_expression
评估为false,则返回值。备注
IIF
是写CASE
表达的简写方式。它计算作为第一个参数传递的布尔表达式,然后根据评估结果返回其他两个参数。也就是说,如果布尔表达式为真,则返回true_value
,如果布尔表达式为false或未知,则返回false_value
。true_value
和false_value
可以是任何类型。适用于布尔表达式,空值处理和返回类型的CASE
表达式的相同规则也适用于IIF
。有关更多信息,请参阅CASE
(Transact-SQL)。将
IIF
翻译成CASE
的事实也对该函数的行为的其他方面产生影响。由于CASE
表达式只能嵌套到10级,因此IIF
语句也可以嵌套到最高级别10.此外,IIF
作为语义上等效的CASE
表达式远程服务于其他服务器,具有所有行为远程CASE
表达。
码
在SQL中实现IIF
函数将类似于以下内容(使用@rsbarro中his answer提供的相同逻辑):
SELECT
COUNT(
IIF(jobs.status_id NOT IN (8,3,11), 1, 0)
) as active_count,
COUNT(
IIF(jobs.due_date < '2011-06-14' AND jobs.status_id NOT IN(8,11,5,3), 1, 0)
) as overdue_count,
COUNT(
IIF(jobs.due_date BETWEEN '2011-06-14' AND '2011-06-15 06:00:00.000000', 1, 0)
) as due_today_count
FROM
"jobs"
WHERE
jobs.creator_id = 5
以上是关于从表中的不同条件中选择COUNT的主要内容,如果未能解决你的问题,请参考以下文章