私は、多くの調査の後、これがどのように行われるかを見つけることができません。
私のウェブ検索はピボット、連結、ケース、サブクエリなどを取得しますが、どれも私にとって問題を完全に解決していません。複数の行から1つの行への質問は役に立ちません。
問題:
1つのテーブルに個人があります。別のテーブルには、これらの個人のアドレス(複数の場合もあります)があります。個人ごとに1つの行(適切な列)に複数の住所を配置するクエリが必要です。
これは、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) | ...
これは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
ちなみに私は与えられたMySQLテーブルを使用していますが、ソリューションの一時テーブルを構築する方法は開いていますが、問題は、最終的な結果に示されているようにデータを組み合わせる方法についてであり、エレガントさについてではありません。元のテーブル。
何千ものレコードが存在する可能性がありますが、1人の個人が6つを超えるアドレスを持っているとは思いません。 (もしも利用可能なアドレスフィールド以上あるならそれが優雅に失敗することは便利でしょうがそれは問題の核心ではありません。)
これが私が正しい質問をしていない単純なものであることを願っています。
どの(名前、住所)の組み合わせが「正しい」組み合わせであるかをどのように決定していますか?
まあ、それが私の問題の最初の50%かもしれません。すべての住所は、個人の行に書き込まれるという点で「正しい」ものです。たとえば、IndividualNumber 7はLittleLebowskiです。彼には3つの住所があり、3つすべてが最終結果のその個人の行に表示されます。私の想定では、最初に「出現」するものが最初のアドレスとして入力されます。 (自動インクリメントされた値を持つ一時テーブル?)レコードの順序についての質問に答えたら、問題の残りの50%は、それらをその個人の行の対応する列に書き込むことです。
質問は3つの主な操作に分けることができます。
IndividualNumber
で分割する(変数を使用)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
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
Address1
、Address2
、...の順序付け方法がまだわからないため、ORDER BY inf.IndividualNumber
を使用して、特定の順序でIndividualNumber
でパーティション化していません。
IndividualNumber
でパーティション分割し、IndividualAddressStreet
で順序付けられたパーティションのメンバーに番号を付ける場合は、ORDER BY inf.IndividualNumber, inf.IndividualAddressStreet
に置き換えることができます。
IndividualNumber
の各パーティションの各行に一意のrow
値が設定されると、それを使用して行を列に転置/ピボットできます。
MySQLはPIVOT
演算子を実装していません。データはGROUP BY d.IndividualNumber
を使用して列Xに移動およびピボットできます。転置された列ごとに、CASE 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
...
これには3つのグループしか含まれていませんが、6個またはN個のグループに簡単に拡張できます。
最終的にIndividualsTable
は、名前と色を目的の出力に追加するために、ピボットサブクエリにLEFT 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
;