如何在MySQL中创建动态数据透视表

时间:2014-03-04 15:26:30

标签: mysql database pivot pivot-table crosstab

我在MySQL中生成数据透视表时遇到问题,并想知道是否有人可以给我任何提示和一些文档,这样我就可以最终解决这个问题了。

我的问题如下:

我的数据库中有2个表。 clients包含客户信息,例如姓名,ssn和一些个人数据。在cli_location表中是客户位置:地址,电话号码,手机等。

有时我们需要根据位置等标准进行选择,以便在特定城市接客户。我们还根据cpf进行查询,以获取特定客户的信息。

我经常需要跨越这两张桌子。我目前正在做left joinleft join的问题在于,有时客户端有多个电话,每个电话会为每个电话生成新行。

在研究如何改善这种行为时,我发现了数据透视表,但是我无法理解它们。

第一个表(客户):

╔════╦══════╦═══════╦════════════╦═══════╦════════╗
║ id ║ name ║  ssn  ║  dt_birth  ║ store ║ value  ║
╠════╬══════╬═══════╬════════════╬═══════╬════════╣
║  1 ║ john ║ 12345 ║ 1991-11-04 ║   318 ║ 34.33  ║
║  2 ║ john ║ 12345 ║ 1991-11-04 ║   318 ║ 654.44 ║
║  3 ║ john ║ 12345 ║ 1991-11-04 ║   212 ║ 238.00 ║
║  4 ║ alex ║ 54321 ║ 1988-05-20 ║   321 ║ 334.44 ║
╚════╩══════╩═══════╩════════════╩═══════╩════════╝

第2个表(cli_location):

╔════╦══════╦═══════╦══════════╦════════╦═════════╦═══════╦══════════╗
║ id ║ name ║  ssn  ║ address  ║  city  ║  state  ║  zip  ║   tel    ║
╠════╬══════╬═══════╬══════════╬════════╬═════════╬═══════╬══════════╣
║  1 ║ john ║ 12345 ║ street1  ║ city1  ║ state1  ║ 23443 ║ 23432122 ║
║  2 ║ john ║ 12345 ║ street1  ║ city1  ║ state1  ║ 23443 ║ 98765434 ║
║  3 ║ john ║ 12345 ║ street2  ║ city5  ║ state7  ║ 54323 ║ 65765567 ║
║  4 ║ john ║ 12345 ║ street3  ║ city4  ║ state9  ║ 76543 ║ 44323455 ║
║  5 ║ alex ║ 54321 ║ street34 ║ city30 ║ state33 ║ 43234 ║ 86643457 ║
╚════╩══════╩═══════╩══════════╩════════╩═════════╩═══════╩══════════╝

当使用左连接跨越表时,引用字段为ssn,结果有许多重复的行。我无法改变生产中的数据结构。

我曾想过做类似的事情:

╔════╦══════╦═══════╦════════════╦═══════╦════════╦════════╦════════╦════════╦════════╦══════════╦════════╦═════════╦═══════╦══════════╦════════╦════════╦════════╦══════════╦════════╦════════╦════════╦══════════╦══════════╦══════════╦══════════╗
║ id ║ name ║  ssn  ║  dt_birth  ║ store ║ value  ║ store1 ║ value1 ║ store2 ║ value2 ║ address  ║  city  ║  state  ║  zip  ║ address1 ║ city1  ║ state1 ║  zip1  ║ address2 ║ city2  ║ state2 ║  zip2  ║   tel    ║   tel1   ║   tel2   ║   tel3   ║
╠════╬══════╬═══════╬════════════╬═══════╬════════╬════════╬════════╬════════╬════════╬══════════╬════════╬═════════╬═══════╬══════════╬════════╬════════╬════════╬══════════╬════════╬════════╬════════╬══════════╬══════════╬══════════╬══════════╣
║  1 ║ john ║ 12345 ║ 1991-11-04 ║   318 ║ 34.33  ║ 318    ║ 654.44 ║ 212    ║ 238.00 ║ street1  ║ city1  ║ state1  ║ 23443 ║ street2  ║ city5  ║ state7 ║ 54323  ║ street3  ║ city4  ║ state9 ║ 76543  ║ 23432122 ║ 98765434 ║ 65765567 ║ 44323455 ║
║  4 ║ alex ║ 54321 ║ 1988-05-20 ║   321 ║ 334.33 ║ (null) ║ (null) ║ (null) ║ (null) ║ street34 ║ city30 ║ state33 ║ 43234 ║ (null)   ║ (null) ║ (null) ║ (null) ║ (null)   ║ (null) ║ (null) ║ (null) ║ (null)   ║ 86643457 ║ (null)   ║ (null)   ║
╚════╩══════╩═══════╩════════════╩═══════╩════════╩════════╩════════╩════════╩════════╩══════════╩════════╩═════════╩═══════╩══════════╩════════╩════════╩════════╩══════════╩════════╩════════╩════════╩══════════╩══════════╩══════════╩══════════╝

这个想法是动态生成列,因为有更多行具有相同类型的信息,如上表所示。即使有2行具有相同的store,字段value的值也会有所不同,因此必须为每个store - value对添加列。与上表中的addressphone字段相同。

如果有人可以给我指点文档,请告诉我任何有助于我学习如何做这类事情的例子或任何事情,我将非常感激!

1 个答案:

答案 0 :(得分:0)

修改

进一步考虑这一点,我确信SQL无法完全满足您的需求。 This answer解释原因,并列出您的选择:

  1. 编写应用程序代码以动态构建查询,或
  2. 运行现有的left join查询,然后编写应用程序代码以将结果操作为所需的格式。
  3. 然而,如果您愿意将多个值合并到一个列中,group_concat可能会让您关闭:

    select
      ssn,
      name,
      group_concat(distinct tel separator ', ') phones,
      group_concat(distinct address separator '; ') addresses
    from
      (select clients.ssn,
        clients.name,
        cli_location.tel,
        concat(cli_location.address, ', ', city, ' ', zip) address
      from clients 
      left join cli_location
        on clients.ssn=cli_location.ssn) c
    group by ssn
    

    产生

    |   SSN | NAME |                                 PHONES |                                                        ADDRESSES |
    |-------|------|----------------------------------------|------------------------------------------------------------------|
    | 12345 | john | 23432122, 44323455, 65765567, 98765434 | street1, city1 23443; street3, city4 76543; street2, city5 54323 |
    | 54321 | alex |                               86643457 |                                           street34, city30 43234 |
    

    http://sqlfiddle.com/#!2/ca287/25

    原始

    如果您想要特定城市的客户列表:

    select clients.ssn, clients.name
    from clients
    inner join cli_location
      using(ssn)
    where city = 'city1'
    group by ssn;
    

    http://sqlfiddle.com/#!2/ca287/3

    你的架构使这比应该更加困难。考虑对其进行规范化,使客户端名称只在一个表中,并将一对多关系(如client:phone)拆分为单独的表。