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

时间:2014-11-13 10:03:20

标签: 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_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中。

感谢。

4 个答案:

答案 0 :(得分:0)

尝试按training_enhancments.reason_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;

答案 1 :(得分:0)

如果您需要在单独的列中进行此操作,则不会提高效率。但是,在MySQL中,您可以使用布尔表达式,结果为1表示true,0表示false,从而使其更具可读性:

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

答案 2 :(得分:0)

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

如果每个Surveyor 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的值(即使没有用于该测量员): -

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;

答案 3 :(得分:0)

最后,我在周围的语言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