将多行数据插入多列

C0M*_*7ER 6 mysql pivot

经过多次搜索,我找不到如何做到这一点。

我的网络搜索得到 Pivots 和 Concats 以及 Cases 和 Subqueries 等,但没有一个能很好地解决我的问题。多行到单行的问题对我没有帮助。

问题:

一张桌子上有个人。另一个表中有这些个人的地址(有时是多个)。我需要一个查询来将每个个人的多个地址放在一行(在适当的列中)。

这是一个带有表和查询的 MySQL Fiddle:

在那个 SQL Fiddle 中,结果有 6 个独特个体的 9 条记录:

Number  | Name              | EyeColor  | HairColor | Street                | City      | State     | Zip   | Street2   | City2 | State2| Zip2  | Street3   | ...
1       | John Smith        | blue      | red       | 100 Pine Street       | New York  | NY        | 10019 |           |       |       | 0     |           | ...
2       | Nancy Jones       | green     | red       | 200 Pine Street       | New York  | NY        | 10018 |           |       |       | 0     |           | ...
3       | Bobby Joe         | blue      | black     | 310 Oak Street        | New York  | NY        | 10018 |           |       |       | 0     |           | ...
7       | Little Lebowski   | green     | blond     | 100 Apple Street      | New York  | NY        | 10018 |           |       |       | 0     |           | ...
7       | Little Lebowski   | green     | blond     | 200 Hickory Street    | New York  | NY        | 10018 |           |       |       | 0     |           | ...
7       | Little Lebowski   | green     | blond     | 1234 Pineapple Street | New York  | NY        | 10018 |           |       |       | 0     |           | ...
2       | Nancy Jones       | green     | red       | 230 Golden Street     | New York  | NY        | 10018 |           |       |       | 0     |           | ...
8       | Sarah Shepard     | brown     | brown     | (null)                | (null)    | (null)    | (null)| (null)    | (null)| (null)| (null)| (null)    | ...
Run Code Online (Sandbox Code Playgroud)

这是我需要最终结果的 SQL Fiddle:

最终结果 SQL Fiddle 总共有 6 个记录,用于 6 个唯一的个人及其在个人行的列中的多个地址:

Number  | Name              | EyeColor  | HairColor | Street            | City      | State | Zip   | Street2           | City2     | State2| Zip2  | Street3               | City3     | State3    | Zip3  | Street4   | City4     | State4    | Zip4  | Street5   | City5     | State5    | Zip5  | Street6   | City6     | State6    | Zip6
1       | John Smith        | blue      | red       | 100 Pine Street   | New York  | NY    | 10019 |                   |           |       | 0     |                       |           |           | 0     |           |           |           | 0     |           |           |           | 0     |           |           |           | 0
2       | Nancy Jones       | green     | red       | 200 Pine Street   | New York  | NY    | 10018 | 230 Golden Street | New York  | NY    | 10018 |                       |           |           | 0     |           |           |           | 0     |           |           |           | 0     |           |           |           | 0
3       | Bobby Joe         | blue      | black     | 310 Oak Street    | New York  | NY    | 10018 |                   |           |       | 0     |                       |           |           | 0     |           |           |           | 0     |           |           |           | 0     |           |           |           | 0
7       | Little Lebowski   | green     | blond     | 100 Apple Street  | New York  | NY    | 10018 | 200 Hickory Street| New York  | NY    | 10018 | 1234 Pineapple Street | New York  | NY        | 10018 |           |           |           | 0     |           |           |           | 0     |           |           |           | 0
8       | Sarah Shepard     | brown     | brown     |                   |           |       | 0     |                   |           |       | 0     |                       |           |           | 0     |           |           |           | 0     |           |           |           | 0     |           |           |           | 0
9       | Joe Profigliani   | brown     | brown     |                   |           |       | 0     |                   |           |       | 0     |                       |           |           | 0     |           |           |           | 0     |           |           |           | 0     |           |           |           | 0
Run Code Online (Sandbox Code Playgroud)

顺便说一下,我正在使用我得到的 MySQL 表,尽管对为解决方案构建临时表的方法持开放态度,但问题是如何组合最终结果中显示的数据,而不是关于原始表。

可能有数千条记录,尽管我不希望任何个人拥有超过 6 个地址。(如果可用的地址字段多的话,让它优雅地失败会很方便,但这不是问题的核心。)

我希望这是一些简单的事情,我只是没有提出正确的问题。

您如何决定哪种(姓名、地址)组合是“正确的”组合?

好吧,我认为这可能是我问题的前 50%。所有地址都是“正确的”,因为它们都被写入个人的行。例如,IndividualNumber 7 是 LittleLebowski,他有 3 个地址,所有三个地址都应出现在最终结果中该个人的行中。我的假设是第一个“出现”的地址作为第一个地址。(具有自动递增值的临时表?)一旦我回答了有关记录顺序的问题,那么另外 50% 的问题就是将它们写入该个人行上的相应列?

Jul*_*eur 7

该问题可以分为 3 个主要操作:

  1. IndividualNumber(使用变量)对行进行分区
  2. 将分区的行透视为列(使用 CASE)
  3. 添加姓名和其他信息并删除 NULL

您可以在此处查看示例:SQL Fiddle

分区行IndividualNumber

此查询的行为类似于 Oracle (>= 10g)、PostgreSQL (>= 8.4) 和 SQL Server (>= 2012) 中可用的 ROW_NUMBER() 窗口函数。

MySQL 没有实现它,它必须使用变量和CASE语句来完成:

  SELECT @row := CASE WHEN inf.IndividualNumber = @id 
      THEN @row + 1 ELSE 1 END as row 
    , @id := inf.IndividualNumber as IndividualNumber
      , inf.IndividualAddressStreet
      , inf.IndividualCity
      , inf.IndividualState
      , inf.IndividualZip
  FROM (SELECT @row := 0, @id := 0) v
    , InfoaboutThemTable as inf 
  ORDER BY inf.IndividualNumber
Run Code Online (Sandbox Code Playgroud)

row为 中的每个IndividualNumber(分区)返回一个从 1 到 n的唯一值InfoaboutThemTable

row     IndividualNumber    IndividualAddressStreet     IndividualCity  IndividualState     IndividualZip
1       1                   100 Pine Street             New York        NY                  10019
1       2                   200 Pine Street             New York        NY                  10018
2       2                   201 Pine Street             New York        NY                  10018
3       2                   230 Golden Street           New York        NY                  10018
4       2                   456 Golden Street           New York        NY                  10018
1       3                   310 Oak Street              New York        NY                  10018
1       7                   100 Apple Street            New York        NY                  10018
2       7                   200 Hickory Street          New York        NY                  10018
3       7                   1234 Pineapple Street       New York        NY                  10018   
Run Code Online (Sandbox Code Playgroud)

因为您还不知道如何订购Address1, Address2, ... 它仅用于ORDER BY inf.IndividualNumberIndividualNumber无特定顺序进行分区。

ORDER BY inf.IndividualNumber, inf.IndividualAddressStreet如果您要分区IndividualNumber并为分区的成员提供编号,则可以替换为IndividualAddressStreet

一旦每个分区的每一行IndividualNumber都有一个唯一的row值,它就可以用于将行转置/旋转到列。

MySQL 没有实现该PIVOT运算符。数据可以使用 a 移动和旋转到 XGROUP BY d.IndividualNumber列,对于每个转置的列, aCASE WHEN row = X THEN ... END与聚合 ( MAX) 一起使用:

MAX(CASE WHEN row = 1 THEN d.IndividualAddressStreet END) AS Street1
MAX(CASE WHEN row = 1 THEN d.IndividualCity END) AS City1
...
MAX(CASE WHEN row = 2 THEN d.IndividualAddressStreet END) AS Street2
...
Run Code Online (Sandbox Code Playgroud)

它只包含 3 个组,但您可以轻松地将其扩展到 6 个或 N 个组。

添加姓名信息:

最后IndividualsTableLEFT JOIN旋转子查询,以便将名称和颜色添加到所需的输出。

NULL使用 将值替换为空字符串COALESCE

完整查询:

SELECT idt.IndividualNumber
    , idt.Name
    , idt.IndividualEyeColor
    , idt.IndividualHairColor
    , COALESCE(grp.Street1, '') as Street1
    , COALESCE(grp.City1, '') as City1
    , COALESCE(grp.State1, '') as State1
    , COALESCE(grp.Zip1, '') as Zip1
    , COALESCE(grp.Street2, '') as Street2
    , COALESCE(grp.City2, '') as City2
    , COALESCE(grp.State2, '') as State2
    , COALESCE(grp.Zip2, '') as Zip2
    , COALESCE(grp.Street3, '') as Street3
    , COALESCE(grp.City3, '') as City3
    , COALESCE(grp.State3, '') as State3
    , COALESCE(grp.Zip3, '') as Zip3
FROM IndividualsTable idt
LEFT JOIN (
    SELECT d.IndividualNumber as IndividualNumber
        , MAX(CASE WHEN row = 1 THEN d.IndividualAddressStreet END) AS Street1
        , MAX(CASE WHEN row = 1 THEN d.IndividualCity END) AS City1
        , MAX(CASE WHEN row = 1 THEN d.IndividualState END) AS State1
        , MAX(CASE WHEN row = 1 THEN d.IndividualZip END) AS Zip1
        , MAX(CASE WHEN row = 2 THEN d.IndividualAddressStreet END) AS Street2
        , MAX(CASE WHEN row = 2 THEN d.IndividualCity END) AS City2
        , MAX(CASE WHEN row = 2 THEN d.IndividualState END) AS State2
        , MAX(CASE WHEN row = 2 THEN d.IndividualZip END) AS Zip2
        , MAX(CASE WHEN row = 3 THEN d.IndividualAddressStreet END) AS Street3
        , MAX(CASE WHEN row = 3 THEN d.IndividualCity END) AS City3
        , MAX(CASE WHEN row = 3 THEN d.IndividualState END) AS State3
        , MAX(CASE WHEN row = 3 THEN d.IndividualZip END) AS Zip3
    FROM
    (
      SELECT @row := CASE WHEN inf.IndividualNumber = @id 
          THEN @row + 1 ELSE 1 END as row 
        , @id := inf.IndividualNumber as IndividualNumber
          , inf.IndividualAddressStreet
          , inf.IndividualCity
          , inf.IndividualState
          , inf.IndividualZip
      FROM (SELECT @row := 0, @id := 0) v
        , InfoaboutThemTable as inf 
      ORDER BY inf.IndividualNumber
    ) d 
    GROUP BY d.IndividualNumber
) grp
    ON grp.IndividualNumber = idt.IndividualNumber
;
Run Code Online (Sandbox Code Playgroud)