Mysql 计算不同列值出现次数的更有效方法?

Mysql 计算不同列值出现次数的更有效方法?,mysql,sql,Mysql,Sql,我看到了一些相关的问题,但它们似乎不是相同的情况,所以我们将不胜感激 我有当前的查询: SELECT COUNT(CASE WHEN training_enhancments.reason_id = 0 THEN 1 END) AS '0Count', COUNT(CASE WHEN training_enhancments.reason_id = 1 THEN 1 END) AS '1Count', COUNT(CASE WHEN training_enhancment

我看到了一些相关的问题,但它们似乎不是相同的情况,所以我们将不胜感激

我有当前的查询:

SELECT
    COUNT(CASE WHEN training_enhancments.reason_id = 0 THEN 1 END) AS '0Count',
    COUNT(CASE WHEN training_enhancments.reason_id = 1 THEN 1 END) AS '1Count',
    COUNT(CASE WHEN training_enhancments.reason_id = 2 THEN 1 END) AS '2Count',
    COUNT(CASE WHEN training_enhancments.reason_id = 3 THEN 1 END) AS '3Count',
    COUNT(CASE WHEN training_enhancments.reason_id = 8 THEN 1 END) AS '4Count',
    ...
    COUNT(CASE WHEN training_enhancments.reason_id = 40 THEN 1 END) AS '40Count',
FROM 
    claims claims 
    INNER JOIN users users ON claims.surveyor_id = users.user_id
    INNER JOIN insurers insurers on claims.insurer_id = insurers.insurer_id
    LEFT JOIN training_enhancments training_enhancments on claims.claim_id = training_enhancments.claim_id
WHERE
    claims.claim_cancelled_id <= 0 AND
    claims.date_completed BETWEEN '2014-10-01 00:00:00' AND '2014-10-31 23:59:59'
GROUP BY claims.surveyor_id;
如何重写COUNT语句以提高效率/可读性?类似于for/while循环,但我不确定它们是否存在于SQL中

谢谢。

尝试通过培训\u enhanctions.reason\u id进行分组,然后在应用程序代码中,您可以使用for/while循环显示40个计数

SELECT
    claims.surveyor_id,
    training_enhancments.reason_id,
    COUNT(*) 
FROM 
    claims claims 
    INNER JOIN users users ON claims.surveyor_id = users.user_id
    INNER JOIN insurers insurers on claims.insurer_id = insurers.insurer_id
    LEFT JOIN training_enhancments training_enhancments on claims.claim_id = training_enhancments.claim_id
WHERE
    claims.claim_cancelled_id <= 0 AND
    claims.date_completed BETWEEN '2014-10-01 00:00:00' AND '2014-10-31 23:59:59'
GROUP BY 
    claims.surveyor_id,
    training_enhancments.reason_id;

如果您需要在单独的列中使用它,您将无法获得更高的效率。但是,在MySQL中,您可以使用布尔表达式,结果为1表示true,0表示false,从而使其更具可读性:

SELECT
    SUM(training_enhancments.reason_id = 0) AS '0Count',
    SUM(training_enhancments.reason_id = 1) AS '1Count',
    ...
FROM ...

如果您需要每个测量员id有一行固定列,那么您当前的解决方案非常好

如果您可以为每个测量者id设置多行,并且可以在调用脚本中处理它们,那么Jaugar Chang的解决方案将是我的选择

如果必须为每个测量员id返回一行,但可以将返回行中的字段拆分为不同的计数,则可以执行以下操作:-

SELECT surveyor_id, GROUP_CONCAT(CONCAT_WS(':', reason_id, reason_count))
(
    SELECT claims.surveyor_id, training_enhancments.reason_id, COUNT(*) AS reason_count
    FROM claims claims 
    INNER JOIN users users ON claims.surveyor_id = users.user_id
    INNER JOIN insurers insurers on claims.insurer_id = insurers.insurer_id
    LEFT JOIN training_enhancments training_enhancments on claims.claim_id = training_enhancments.claim_id
    WHERE claims.claim_cancelled_id <= 0 
    AND claims.date_completed BETWEEN '2014-10-01 00:00:00' AND '2014-10-31 23:59:59'
    GROUP BY claims.surveyor_id, training_enhancments.reason_id
) sub0
GROUP BY surveyor_id;
或强制测量员使用所有原因ID的值,即使该测量员未使用任何原因ID:-

SELECT surveyor_id, GROUP_CONCAT(CONCAT_WS(':', reason_id, reason_count))
(
    SELECT claims.surveyor_id, reasons.reason_id, COUNT(training_enhancments.claim_id) AS reason_count
    FROM claims claims 
    CROSS JOIN (SELECT 0 AS reason_id UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 8 UNION SELECT 40) reasons
    INNER JOIN users users ON claims.surveyor_id = users.user_id
    INNER JOIN insurers insurers on claims.insurer_id = insurers.insurer_id
    LEFT JOIN training_enhancments training_enhancments on claims.claim_id = training_enhancments.claim_id
    WHERE claims.claim_cancelled_id <= 0 
    AND claims.date_completed BETWEEN '2014-10-01 00:00:00' AND '2014-10-31 23:59:59'
    GROUP BY claims.surveyor_id, training_enhancments.reason_id
) sub0
GROUP BY surveyor_id;

最后,我使用周围的语言PHP进行了for循环

它更具可读性吗?值得商榷。当然,这更容易扩展

$numReasons = 38;

$SQL = "SELECT CONCAT(users.user_first_name,IF((users.user_surname<>''),CONCAT(' ',users.user_surname),'')) as 'Surveyor'";
for ($i = 0; $i < $numReasons + 1; $i++) {
    $SQL .= ", COUNT(CASE WHEN training_enhancments.reason_id = $i THEN 1 END) AS '" . $i . "Count' ";
}
$SQL .= "FROM 
    claims claims 
    INNER JOIN users users ON claims.surveyor_id = users.user_id
    INNER JOIN insurers insurers on claims.insurer_id = insurers.insurer_id
    LEFT JOIN training_enhancments training_enhancments on claims.claim_id = training_enhancments.claim_id

您是否需要为每个测量师id带回一行,或者您是否可以为每个测量师id/原因id带回一行?如果是这样的话,您可以按测量员id、原因id进行单个计数和分组。如果你需要确保你有40行,然后交叉连接一个包含你关心的40个原因的表。是的,每行需要带回1个测量员id。Surveyors+原因是一个0-X到0-X的关系,是否可以进行单个计数?不幸的是,这不起作用,因为结果需要按Surveyors id分组,并且有几百个。你的应用程序的语言是什么?如果你只想添加额外的计数,那么你可以使用范围和数组映射来生成它们$numReasons=38$SQL=选择concaturers.user_first_name,IFusers.user_姓氏,CONCAT“”,users.user_姓氏,作为“测量者”。内爆“,”,数组映射函数$n{在训练时返回COUNTCASE\u enhanctions.reason_id=$n然后以“$n.Count”;}结尾,范围0,$numReasons。索赔