如何在MySQL语句/查询中使CASE语句动态化

时间:2014-06-18 08:44:27

标签: php mysql group-by case case-when

我有一张包含年龄,性别,sid和目标名称的表格。我希望按年龄/性别对此进行分组,然后按每个年龄/性别显示前2个最常用的目标名的值。

这是示例表:

Sample Table MySQL Table 1

我设法使用查询获得输出:

SELECT age, gender, 
SUM(CASE WHEN sid = 'Frank.net Life Cover' THEN 1 ELSE 0 END) AS 'Frank.net Life Cover',
SUM(CASE WHEN sid = 'Frank.net Salary Protection' THEN 1 ELSE 0 END) AS 'Frank.net Salary Protection',
SUM(CASE WHEN sid = 'Frank.net Hospital Cash Back' THEN 1 ELSE 0 END) AS 'Frank.net Hospital Cash Back' 
FROM (SELECT uid, sid, goalname, gender, age 
      FROM sampletable 
      WHERE age >=16 
      AND age < 100 
      GROUP BY age, gender);

这是输出:

Sample MySQL Table 2

我想要的输出有点像这样,但关于这一点的是,它不是动态的。添加了新的目标名称,因为我手动将目标名称放在CASE语句中,所以这不会适用。此外,我只需要显示每个年龄/性别最常用的前2个目标名。

注意:如果您无法显示前2名并且只显示每个目标名的总数,那就没关系。我想我可以通过比较PHP中每个目标名的总数来获得前两名。我只需要一个动态SQL查询。

谢谢!

2 个答案:

答案 0 :(得分:1)

问题在于你要使用不同数量的列进行着陆,这样处理起来很麻烦(并且可能更容易将每个列作为不同的行返回)

使用php动态构建查询是可能的,虽然我不想在现场情况下这样做: -

<?php 

$sql = "SELECT DISTINCT goalname FROM sampletable";

if ($result = $mysqli->query($sql)) 
{
    $sum_col = array();
    while ($row = $result->fetch_row()) 
    {
        $sum_col[] = "SUM(CASE WHEN goalname= '".$mysqli->real_escape_string($row['goalname'])."' THEN 1 ELSE 0 END) AS '".$mysqli->real_escape_string($row['goalname'])."'"
    }

    if (count($sum_col) > 0)
    {
        $sql = "SELECT age, 
                    gender, 
                    ".implode(",", $sum_col)."
                    FROM  sampletable 
                    WHERE age >=16 
                    AND age < 100 
                    GROUP BY age, gender";

        if ($result = $mysqli->query($sql)) 
        {
        }   
    }
}
?>

但是我建议稍后再做一个简单的分组选择并对格式进行排序会更容易: -

SELECT age, 
    gender, 
    goalname,
    COUNT(*)
FROM  sampletable 
WHERE age >=16 
AND age < 100 
GROUP BY age, gender, goalname

或者如果您需要每个人的每个目标名称,无论他们是否选择了它: -

SELECT age, 
    gender, 
    sub0.goalname,
    COUNT(sampletable.sid)
FROM  (SELECT DISTINCT goalname FROM sampletable) sub0
LEFT OUTER JOIN sampletable
ON sub0.goalname = sampletable.goalname
WHERE age >=16 
AND age < 100 
GROUP BY age, gender, sub0.goalname

获得前2名有点复杂,而且你的当前输出在逻辑上是不可能的(因为列指的是不同的行)

编辑 - 获得最高的2对夫妇就像这样完成,但是将两个计数都收回到1列(用##分隔 - 将其更改为您的目标名称​​永远不会包含的内容): -

SELECT age, gender, SUBSTRING_INDEX(GROUP_CONCAT(CONCAT_WS('=', goalname, goalcount) ORDER BY goalcount DESC SEPARATOR '##'), '##', 2)
FROM
(
    SELECT age, 
        gender, 
        goalname,
        COUNT(sid) AS goalcount
    FROM user
    WHERE age >=16 
    AND age < 100 
    GROUP BY age, gender, goalname
) sub1
GROUP BY age, gender;

SQL小提琴: -

http://sqlfiddle.com/#!9/9cc8f/4

答案 1 :(得分:0)

最好通过规范化拆分表。并将sid,goalname放入另一个表中 并使用sid作为主表中的外键。这样,您可以从其他表动态检查值,而不是硬编码。

SELECT s.age, s.gender, count(s.sid),p.goalname 
FROM sampletable s,proposedtable p
where s.sid=p.sid and s.age >=16 AND s.age < 100
group by s.age,s.gender