簡體   English   中英

如何簡化復雜的mysql全外部聯接

[英]How to simplify a complex mysql full outer join

我試圖在Mysql中創建一個完全外部聯接。 我找到了基本問題的幾個答案,並且正在使用“聯合”使其正常工作。 但是,如果不依靠創建一些臨時表,就無法獲得正確的語法。 我嘗試不使用表來生成查詢,但是我始終無法獲得結果來包含帶有空partner_id的條目。

這是減少的數據集,已經由meeting_id過濾:

+-----+---------+--------+------------+------------+
| pid | first   | gender | meeting_id | partner_id |
+-----+---------+--------+------------+------------+
|   2 | Vicki   | F      |         74 |       NULL |
|  54 | Fazal   | M      |         74 |          4 |
|   4 | Lisa    | F      |         74 |         54 |
|  10 | Rod     | M      |         74 |         57 |
|  57 | Kellee  | F      |         74 |         10 |
|  11 | Jake    | M      |         74 |         55 |
|  55 | Rosa    | F      |         74 |         11 |
|  47 | Ralph   | M      |         74 |         46 |
|  46 | Holly   | F      |         74 |         47 |
|  40 | Wes     | M      |         74 |         12 |
|  12 | Lori    | F      |         74 |         40 |
|   5 | Richard | M      |         74 |          6 |
|   6 | Rita    | F      |         74 |          5 |
|  15 | John    | M      |         74 |         16 |
|  16 | Corie   | F      |         74 |         15 |
+-----+---------+--------+------------+------------+

我的原始查詢如下所示:

set @mtg=74;

select
    a.pid,
    concat(a.first, ' ', a.last) as guy,
    a.issub as guysub,
    b.pid,
    concat(b.first, ' ', b.last) as gal,
    b.issub as galsub,
    b.partner_id
from 
    scheduled_players a
    left outer join
    scheduled_players b
    on a.partner_id = b.pid
where
    a.gender = 'M' and a.meeting_id = @mtg and b.meeting_id = @mtg

union

select
    a.pid,
    concat(a.first, ' ', a.last) as guy,
    a.issub as guysub,
    b.pid,
    concat(b.first, ' ', b.last) as gal,
    b.issub as galsub,
    b.partner_id
from 
    scheduled_players a
    left outer join
    scheduled_players b
    on b.partner_id = a.pid
where
    a.gender = 'M' and a.meeting_id = @mtg and b.meeting_id = @mtg

;

該查詢未返回帶有空partner_id的單個條目。 我在StackOverflow上閱讀了許多答案,似乎where子句可能導致外部聯接恢復為內部聯接。 就我而言,我沒有看到這種情況如何發生,但是為了測試這一點,我決定創建臨時表以包含“ where”子句元素。 我需要為“ guys”和“ gals”中的每個人創建2個臨時表,因為我在查詢中有2次表。 結果在這里:

set @mtg=74;

create temporary table if not exists 
meeting_guys as select * from scheduled_players
where meeting_id = @mtg and gender='M';

create temporary table if not exists 
meeting_gals as select * from scheduled_players
where meeting_id = @mtg and gender='F';

create temporary table if not exists 
meeting_guys2 as select * from scheduled_players
where meeting_id = @mtg and gender='M';

create temporary table if not exists 
meeting_gals2 as select * from scheduled_players
where meeting_id = @mtg and gender='F';


select
    a.pid,
    concat(a.first, ' ', a.last) as guy,
    a.issub as guysub,
    b.pid,
    concat(b.first, ' ', b.last) as gal,
    b.issub as galsub,
    b.partner_id
from 
    meeting_guys a
    left outer join
    meeting_gals b
    on a.partner_id = b.pid

union

select
    a.pid,
    concat(a.first, ' ', a.last) as guy,
    a.issub as guysub,
    b.pid,
    concat(b.first, ' ', b.last) as gal,
    b.issub as galsub,
    b.partner_id
from 
    meeting_guys2 a
    right outer join
    meeting_gals2 b
    on b.partner_id = a.pid
;

事實證明這是可行的,並且我收到了預期的結果(我刪除了姓氏,因為這些是真實的人):

+------+---------+--------+------+--------+--------+------------+
| pid  | guy     | guysub | pid  | gal    | galsub | partner_id |
+------+---------+--------+------+--------+--------+------------+
|   54 | Fazal   |      0 |    4 | Lisa   |      0 |         54 |
|   10 | Rod     |      0 |   57 | Kellee |      0 |         10 |
|   11 | Jake    |      0 |   55 | Rosa   |      0 |         11 |
|   47 | Ralph   |      0 |   46 | Holly  |      0 |         47 |
|   40 | Wes     |      0 |   12 | Lori   |      0 |         40 |
|    5 | Richard |      0 |    6 | Rita   |      0 |          5 |
|   15 | John    |      0 |   16 | Corie  |      0 |         15 |
| NULL | NULL    |   NULL |    2 | Vicki  |      0 |       NULL |
+------+---------+--------+------+--------+--------+------------+

我可以得到想要的結果,但是我不明白為什么先前的查詢不起作用。 幸運的是,我有一個可行的解決方案,但是我真的很想知道是否有更好,更優化的方法。

首先要指出的是,這未經測試,因此您可能只需要對其進行調整,但聽起來比修復奇數錯誤的能力還強。 如果您確實需要我弄清楚為什么我做了某件事,或者您需要我來解決某件事,只需說一句話。

為了解釋為什么您的第一次嘗試意外消除了空記錄,您正確的是您的where子句正在執行此操作。 對於左連接, a.meeting_id = @mtg and b.meeting_id = @mtg可以使用a.meeting_id = @mtg和(b.meeting_id = @mtg或b.meeting_id為null)代替a.meeting_id = @mtg and b.meeting_id = @mtg加入后,您將在左側表格中檢查null。

至於替代解決方案,我使用了一個臨時表將結果集限制為僅匹配的Meeting_id的早期(以提高性能),以防您的表很大,然后在派生表中篩選M / F。

希望對您有幫助。

set @mtg=74;

create temporary table if not exists 
meeting as 
select
    pid,
    concat(first, ' ', last) as full_name,
    issub,
    partner_id,
    meeting_id,
    gender
from scheduled_players
where meeting_id = @mtg;

select
    M.pid,
    M.full_name as guy,
    M.issub as guysub,
    F.pid,
    F.full_name as gal,
    F.issub as galsub,
    F.partner_id
from 
    (select * from meeting where gender = 'M') M
    left outer join (select * from meeting where gender = 'F') F
        on M.partner_id = F.pid
UNION
select
    M.pid,
    M.full_name as guy,
    M.issub as guysub,
    F.pid,
    F.full_name as gal,
    F.issub as galsub,
    F.partner_id
from 
    (select * from meeting where gender = 'M') M
    right outer join (select * from meeting where gender = 'F') F
        on F.partner_id = M.pid

編輯

如果性能不是問題,那么也許完全忘記temp表,然后直接在派生表中引用該表就更簡單了;

select concat(first, ' ', last) as full_name, * from scheduled_players where gender = 'M' and meeting_id = @mtg
select concat(first, ' ', last) as full_name, * from scheduled_players where gender = 'F' and meeting_id = @mtg

您還可以創建一個臨時表,然后在單獨的查詢中插入和更新該臨時表。

一天結束時對您有用的一切。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM