如何對來自相同兩個表但來自兩個不同結果集和/或條件的相同列進行分組
我在想出一個應該很簡單的查詢時遇到了麻煩。
最初,我有兩個數據表,可以從中生成聯合結果集;一個事件表和一個組表(想想社區或組織)。我將使用查詢來獲取事件數據,例如事件名稱、ID、託管事件的組(僅限單個 ID)等。每個事件和組都有自己唯一的 ID 號,由 AUTO_INCREMENT 給出。我會使用以下查詢:
SELECT g.group_id, g.name, prev_id, activity_state+0, state, first_event_id, last_event_id, GROUP_CONCAT(e.event_id ORDER BY start_date_time SEPARATOR ','), GROUP_CONCAT(e.name ORDER BY start_date_time SEPARATOR '__'), GROUP_CONCAT(start_date_time ORDER BY start_date_time SEPARATOR ',') AS first_dates, GROUP_CONCAT(end_date_time ORDER BY start_date_time SEPARATOR ',') FROM events e INNER JOIN groups g ON e.group_id=g.group_id WHERE start_date_time BETWEEN ? AND ? GROUP BY g.name ORDER BY first_dates
兩個問號代表準備好的語句中的兩個綁定日期和時間。這個查詢可以很好地工作。
但是,我最近更新了數據庫的結構以包含所謂的“聯合事件”,其中多個組一起舉辦相同的事件。我添加了一個joint_event表,它只包含一個event_id 列和一個group_id 列。相同的事件 ID 在表中出現多次(至少兩次),用於指示哪些組主持了特定的事件。聯合事件也被添加到事件表中,但其 ID 為0(零)。
我現在需要一個與上述功能相似的查詢。查詢必須包括來自事件表和組表連接條件的初始結果集,以及與聯合事件表中相同條件匹配的任何联合事件的發生。它們必須適當地分組在一起,這樣我就不會得到相同數據的重複(每個組應該出現在自己的行中,並且每組只有一行)。
另外,SQL-89 語法中的連接條件如下:
events.group_id = groups.group_id
(給出大部分結果,至少 98%,加上……)
events.event_id = joint_events.event_id AND joint_events.group_id = groups.group_id
(聯合活動)
我曾嘗試使用 UNION,但它似乎不支持按返回的整個數據集進行分組。我曾嘗試使用子查詢,但在使用別名來描述兩個單獨數據結果集中的相同列時遇到問題,因為它通常會產生“不明確”的列名錯誤。使用 DISTINCT 不起作用,因為它要麼刪除彼此具有完全相同名稱的事件(這些需要保留),要麼在未應用於需要分組的所有四個列時在分組列中創建不一致. 我最接近的是一個查詢,它導致聯合事件數據與其他數據分開,而不是被分組到其他數據中;或數據被包含,但事件數據被複製。
我不能在任何地方使用 NULL,或者使用兩個完全獨立的查詢,否則我將不得不重構我的 PHP 腳本,並且可能會使使用 PHP 對數據進行排序的操作效率低下。
提前致謝。
我解決了。該解決方案側重於開頭的組 ID、事件 ID 和 start_date_time 欄位,這些欄位由相關條件過濾並放入派生表中。然後圍繞它放置一個外部查詢,負責收集所有必需的欄位,將它們分組在一起,並按派生的“first_dates”欄位排序。該查詢以 SQL-89 語法顯示在下面(同樣,問號表示準備好的語句格式的綁定日期):
SELECT g.group_id, g.name, prev_id, activity_state+0, state, first_event_id, last_event_id, GROUP_CONCAT(e.event_id ORDER BY e.start_date_time), GROUP_CONCAT(e.name ORDER BY e.start_date_time SEPARATOR '__'), GROUP_CONCAT(e.start_date_time ORDER BY e.start_date_time) AS first_dates, GROUP_CONCAT(end_date_time ORDER BY e.start_date_time) FROM events e, groups g, (SELECT DISTINCT g.group_id, e.event_id, start_date_time FROM events e, groups g, joint_events j WHERE (e.group_id=g.group_id OR (e.event_id=j.event_id AND j.group_id=g.group_id)) AND start_date_time BETWEEN ? AND ?) t WHERE g.group_id=t.group_id AND e.event_id=t.event_id GROUP BY g.group_id ORDER BY first_dates
請記住,這樣的查詢是這樣操作的:
JOIN
所有表一起,生成一個“大”臨時表,其中包含所有未被過濾掉的組合。- 然後做聚合(
SUM
,,GROUP_CONCAT
等)一個常見的問題是由於所有的組合
SUMs
而COUNTs
被誇大了。在您的情況下,GROUP_CONCAT
可能有重複;這可以通過說來處理GROUP_CONCAT(DISTINCT ...)
。一個常見的解決方案是專注於聚合,使用最少的
JOINs
來獲得正確的聚合,然後JOIN
關注其餘的表。有時可行的另一種解決方案是將 a 替換為計算“查找”值
JOIN
的子查詢(在部分中)(例如將 an 映射到 a )。SELECT``id``name
您必須使用舊版本的 MySQL;新版本不喜歡你
GROUP BY one-column
在列出SELECT
.對不起,這只是“揮手”,但您的問題也缺少細節,例如“我添加時…”的詳細資訊
SHOW CREATE TABLE
,指定每列屬於哪個表等。