【问题标题】:mysql query to dynamically convert row data to columnsmysql查询将行数据动态转换为列
【发布时间】:2009-10-21 09:51:49
【问题描述】:

我正在处理数据透视表查询。 架构如下

Sno、名称、地区

同名可能出现在多个地区例如以样本数据为例

1 Mike CA
2 Mike CA
3 Proctor JB
4 Luke MN
5 Luke MN
6 Mike CA
7 Mike LP
8 Proctor MN
9 Proctor JB
10 Proctor MN
11 Luke MN

如您所见,我有一组 4 个不同的地区(CA、JB、MN、LP)。现在我想通过将名称映射到地区来获取为其生成的数据透视表

Name CA JB MN LP
Mike 3 0 0 1
Proctor 0 2 2 0
Luke 0 0 3 0

我为此编写了以下查询

select name,sum(if(District="CA",1,0)) as "CA",sum(if(District="JB",1,0)) as "JB",sum(if(District="MN",1,0)) as "MN",sum(if(District="LP",1,0)) as "LP" from district_details group by name

但是,地区可能会增加,在这种情况下,我将不得不再次手动编辑查询并将新地区添加到其中。

我想知道是否有一个查询可以动态获取不同地区的名称并运行上述查询。我知道我可以通过一个程序来完成并即时生成脚本,还有其他方法吗?

我之所以这么问,是因为查询“select distinct(districts) from district_details”的输出将返回给我一列,每行都有地区名称,我希望将其转换为列。

【问题讨论】:

  • 看看mysql的GROUP_CONCAT()函数。

标签: sql mysql pivot-table


【解决方案1】:

您根本无法让静态 SQL 语句返回可变数量的列。每次不同区的数量变化时都需要建立这样的语句。为此,您首先执行一个

SELECT DISTINCT District FROM district_details;

这将为您提供有详细信息的地区列表。然后,您构建一个 SQL 语句迭代先前的结果(伪代码)

statement = "SELECT name "

For each row returned in d = SELECT DISTINCT District FROM district_details 
    statement = statement & ", SUM(IF(District=""" & d.District & """,1 ,0)) AS """ & d.District & """" 

statement = statement & " FROM district_details GROUP BY name;"

并执行该查询。然后,您需要在代码中处理可变列数的处理

【讨论】:

    【解决方案2】:

    a) MySQL 存储过程不支持“For each”。 b) 存储过程不能使用所谓的动态 SQL 语句从连接的字符串中执行准备好的语句,也不能返回具有多个不同行的结果。 c) 存储函数根本无法执行动态 SQL。

    一旦你有了一个好主意,跟踪它是一场噩梦,而且每个人似乎都在他们思考“为什么有人想要......”之前揭穿它

    我希望你能找到你的解决方案,我仍在寻找我的解决方案。 我得到的关闭是

    (请原谅伪代码)

    -> 到存储过程,构建函数...

    1) 创建临时表 2)使用您的 if 语句将数据从列加载到临时表 3) 将临时表加载到存储过程中的 INOUT 或 OUT 参数,就像调用表一样...如果你可以让它返回多于一行

    还有一个提示... 将您的地区存储为表格常规样式,加载它并通过循环标记为活动的地区进行迭代,以动态连接一个查询字符串,该查询字符串可能是所有系统关心的纯文本

    然后使用;

    从@yourqyerstring 准备stmName; 执行stmName; 解除分配准备stmName;

    (也可以在 mysql 论坛的存储过程部分找到更多信息)

    每次运行一组不同的区域,而无需重新设计您的原始进程

    也许数字形式更容易。 我处理表格中的纯文本内容,没有什么可求和、计数或累加

    【讨论】:

    • "b) 存储过程不能使用所谓的动态 SQL 语句从连接的字符串中执行准备好的语句,也不能返回具有多个不同行的结果。c) 存储函数根本不能执行动态 SQL。 "那是错误的。 MySQL 存储过程可以执行动态 SQL,也可以连接和准备,但不能嵌套(即不能使用 EXECUTE 执行另一个 PREPARE/EXECUTE 语句)。见:dev.mysql.com/doc/refman/5.0/en/…
    • "a) "对于每个 " 在 MySQL 存储过程中不受支持。"虽然这是真的,但 MySQL SP 内部使用 REPEAT-UNTIL/LOOP 支持循环。见:dev.mysql.com/doc/refman/5.0/en/repeat-statement.html
    • 我不得不说,尽管我有上述cmets,但我有偏见:我不相信SP,我谴责它的使用。 SP 是邪恶的,除非它是严格需要的,并且所有其他替代方案(如代码 + 缓存)都被证明更糟糕。
    【解决方案3】:

    以下假设您需要不同(名称/地区)对的匹配。 IE。 Luke/CA 和 Duke/CA 会产生两个结果:

    SELECT name, District, count(District) AS count
    FROM district_details
    GROUP BY District, name
    

    如果不是这种情况,只需从 GROUP BY 子句中删除名称。

    最后,请注意,我将 sum() 切换为 count(),因为您尝试对所有分组行进行计数,而不是获取值的总和。

    【讨论】:

    • 感谢您的意见,但这不是我想要的。我想显示所有地区所有名称的地区计数。因此,如果对于卢克或杜克,我想获得每个地区的计数,如果该地区不存在,则为 0。我也相信 sum 1 n 次(我在查询中这样做)会做同样的事情。
    【解决方案4】:

    通过上面@cballou 的评论,我能够执行这种功能,这不完全是 OP 所要求的,但适合我的类似情况,所以在这里添加它以帮助后来者。

    普通选择语句:

    SELECT d.id ID,
           q.field field,
           q.quota quota
      FROM defaults d
      JOIN quotas q ON d.id=q.default_id
    

    垂直结果:

    ID field  quota
    1  male   25
    1  female 25
    2  male   50
    

    使用 group_concat 选择语句:

    SELECT d.id ID,
           GROUP_CONCAT(q.fields SEPARATOR ",") fields,
           GROUP_CONCAT(q.quotas SEPARATOR ",") quotas
      FROM defaults d
      JOIN quotas q ON d.id=q.default_id
    

    然后我得到逗号分隔的“字段”和“配额”字段,然后我可以在以后轻松地以编程方式处理它们。

    水平结果:

    ID fields      quotas
    1  male,female 25,25
    2  male        50
    

    魔法!

    【讨论】:

      猜你喜欢
      • 2013-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-21
      相关资源
      最近更新 更多