2017-12-25 20 views
0

をグループ化するORDERとGROUP BY私は2つのテーブルがあります。のMySQL - JOINを、

CREATE TABLE Person { 
    ID INT PRIMARY KEY, 
    Name VARCHAR(50) NOT NULL, 
    Surname VARCHAR(50) NOT NULL 
} 

CREATE TABLE Address { 
    ID INT PRIMARY KEY, 
    ID_Person INT NOT NULL, 
    Street VARCHAR(50), 
    HouseNumber VARCHAR(15), 
    City VARCHAR(75), 
    Zipcode VARCHAR(10), 
    CountryCode CHAR(2), 
    IsPrimary TINYINT(1) DEFAULT 0 
} 

一人一人がmuptipleアドレスを持つことができますが、最大1つがプライマリすることができ(IsPrimary = 1を) 。

1つの住所の人のリストを取得したいと思います。人が一次アドレスを持っている場合は、それが重要でない場合は、提供されなければならない。

私はこのクエリを持っている:

SELECT 
    p.Name, 
    p.Surname, 
    a.Street, 
    a.Housenumber, 
    a.City, 
    a.Zipcode 
FROM 
    Person AS p   
LEFT JOIN (select * from Address ORDER BY IsPrimary DESC) AS a ON p.ID = a.ID_Person 
GROUP BY p.ID 

が、それは私が期待する結果を提供していません。私はGROUP BYを実行するときに結合されたテーブルの最初の行が取得されると予想しましたが、そうではありません。

類似の質問がありましたhereしかし、解決策は私の状況ではむしろ困難です。

答えて

1

ORDER BYサブクエリでは通常、クエリの速度が遅くなります。このクエリは、第二の問題がある

SELECT 
    p.Name, 
    p.Surname, 
    a.Street, 
    a.Housenumber, 
    a.City, 
    a.Zipcode 
FROM 
    Person AS p   
LEFT JOIN Address AS a ON p.ID = a.ID_Person 
GROUP BY p.ID ORDER BY a.isPrimary 

を:それはANSI準拠していないので、MySQLはANSIに準拠し実行されていないときには、MySQLだけで動作 かわりに、結果を注文する必要があります。

仮定: Addressの表に2行の1 p.IDがあります。 Address.CityにはGROUP関数が適用されていません。データベースにはどのように表示するかはどのように分かりますか?そうではありませんので、あなたはランダムなものを見ます。これを防ぐには、グループに属していないすべての列に関数を適用します(またはグループの列を配置します)。

+0

これは、ありがとうございます! – Zbynek

1

MySQL 8.0では、これはランキングクエリとして最適です。

WITH PersonAddress AS (
    SELECT 
    p.Name, 
    p.Surname, 
    a.Street, 
    a.Housenumber, 
    a.City, 
    a.Zipcode, 
    ROW_NUMBER() OVER (PARTITION BY p.ID ORDER BY a.IsPrimary DESC) AS rn 
    FROM Person AS p 
    LEFT OUTER JOIN Address AS a ON p.ID = a.ID_Person 
) 
SELECT * FROM PersonAddress WHERE rn = 1; 

以前のバージョンのウィンドウング機能は利用できません。回避策はセッション変数を使用することです:

SELECT 
    t.Name, 
    t.Surname, 
    t.Street, 
    t.Housenumber, 
    t.City, 
    t.Zipcode 
FROM (
    SELECT 
    p.Name, 
    p.Surname, 
    a.Street, 
    a.Housenumber, 
    a.City, 
    a.Zipcode, 
    IF(p.ID = @pid, @rn:[email protected]+1, @rn:=1) AS rn, 
    @pid := p.ID 
    FROM (SELECT @pid:=0, @rn:=1) AS _init 
    CROSS JOIN Person AS p 
    LEFT OUTER JOIN Address AS a ON p.ID = a.ID_Person 
    ORDER BY p.ID, a.IsPrimary DESC 
) AS t 
WHERE t.rn = 1;