2010-03-16 70 views
2

MySQL v5.0.58。當'WITH'不可用時避免重複的子查詢

表,以略去了外鍵約束等和其他不相關的細節:

CREATE TABLE `fixture` (
    `id` int(11) NOT NULL auto_increment, 
    `competition_id` int(11) NOT NULL, 
    `name` varchar(50) NOT NULL, 
    `scheduled` datetime default NULL, 
    `played` datetime default NULL, 
    PRIMARY KEY (`id`) 
); 

CREATE TABLE `result` (
    `id` int(11) NOT NULL auto_increment, 
    `fixture_id` int(11) NOT NULL, 
    `team_id` int(11) NOT NULL, 
    `score` int(11) NOT NULL, 
    `place` int(11) NOT NULL, 
    PRIMARY KEY (`id`) 
); 

CREATE TABLE `team` (
    `id` int(11) NOT NULL auto_increment, 
    `name` varchar(50) NOT NULL, 
    PRIMARY KEY (`id`) 
); 

其中:

  • 平局將設置resultplace改爲0
  • resultplace將另外包含代表第一位,第二位等的整數

該任務是返回一個字符串,該字符串描述給定團隊的給定比賽中最近播放的結果。如果給定的隊伍勝利,則格式應該是「def X隊伍,Y隊伍」,如果給定的隊伍輸了,則輸給「X隊伍」,如果有平局,則應該「與X隊伍一起」。是的,理論上每個燈具可以有兩個以上的隊伍(儘管1v 1將是最常見的情況)。

這工作,但感覺很低效:

SELECT CONCAT(
    (SELECT CASE `result`.`place` 
     WHEN 0 THEN "drew with" 
     WHEN 1 THEN "def" 
     ELSE "lost to" 
     END 
    FROM `result` 
    WHERE `result`.`fixture_id` = 
     (SELECT `fixture`.`id` FROM `fixture` 
     LEFT JOIN `result` ON `result`.`fixture_id` = `fixture`.`id` 
     WHERE `fixture`.`competition_id` = 2 
     AND `result`.`team_id` = 1 
     ORDER BY `fixture`.`played` DESC 
     LIMIT 1) 
    AND `result`.`team_id` = 1), 
    ' ', 
    (SELECT GROUP_CONCAT(`team`.`name`) 
    FROM `fixture` 
    LEFT JOIN `result` ON `result`.`fixture_id` = `fixture`.`id` 
    LEFT JOIN `team` ON `result`.`team_id` = `team`.`id` 
    WHERE `fixture`.`id` = 
     (SELECT `fixture`.`id` FROM `fixture` 
     LEFT JOIN `result` ON `result`.`fixture_id` = `fixture`.`id` 
     WHERE `fixture`.`competition_id` = 2 
     AND `result`.`team_id` = 1 
     ORDER BY `fixture`.`played` DESC 
     LIMIT 1) 
    AND `team`.`id` != 1) 
) 

有我錯過了什麼真的很明顯,還是應該我根本就沒有嘗試這樣做在一個查詢?還是當前的困難反映了糟糕的桌子設計?

+0

我剛剛意識到'失去'的情況下需要更仔細的處理,因爲它確實應該只列出勝出的球隊。 – 2010-03-16 01:04:39

+0

有多少隊可以參加夾具? – outis 2010-03-16 20:26:20

+0

我沒有設置邊界,因此我當前的表格設計中夾具與結果分開。有些遊戲(我們在這裏說電腦遊戲)每場比賽有三面或更多面,例如戰爭黎明等RTS。 – 2010-03-17 05:37:36

回答

1

嘗試選擇您需要的數據(團隊名稱和place爲目標團隊),然後將其合併。對於每個燈具的兩支球隊:

SELECT CASE `recent`.`place` 
     WHEN 0 THEN CONCAT("drew with ", other_name) 
     WHEN 1 THEN CONCAT("def ", other_name, ", ", targ_name) 
     ELSE CONCAT("lost to ", other_name) 
    END 
FROM (SELECT rtarg.place, targ.name AS targ_name, other.name AS other_name 
     FROM `fixture` 
     JOIN `result` AS rtarg ON `rtarg`.`fixture_id` = `fixture`.`id` 
     JOIN `team` AS targ ON `rtarg`.`team_id` = `targ`.`id` 
     JOIN `result` AS rother ON `rother`.`fixture_id` = `fixture`.`id` 
     JOIN `team` AS other ON `rother`.`team_id` = `other`.`id` 
     WHERE `fixture`.`competition_id` = 2 
      AND `rtarg`.`team_id` = @targ 
      AND `rother`.`team_id` != @targ 
     ORDER BY `fixture`.`played` DESC 
     LIMIT 1) AS `recent`; 

處理每個燈具超過兩個團隊可以以最小的改動來完成,但其他子查詢也將工作。

SELECT CASE `recent`.`place` 
     WHEN 0 THEN CONCAT("drew with ", other_names) 
     WHEN 1 THEN CONCAT("def ", other_names, "; ", targ_name) 
     ELSE CONCAT("lost to ", other_names) 
    END 
FROM (SELECT rtarg.place, targ.name AS targ_name, GROUP_CONCAT(other.name SEPARATOR ', ') AS other_names 
     FROM `fixture` 
     JOIN `result` AS rtarg ON `rtarg`.`fixture_id` = `fixture`.`id` 
     JOIN `team` AS targ ON `rtarg`.`team_id` = `targ`.`id` 
     JOIN `result` AS rother ON `rother`.`fixture_id` = `fixture`.`id` 
     JOIN `team` AS other ON `rother`.`team_id` = `other`.`id` 
     WHERE `fixture`.`competition_id` = 2 
      AND `targ`.`id` = @targ 
      AND `rother`.`team_id` != @targ 
      AND ((rtarg.place<=1 AND rother.place >= rtarg.place) 
      OR (rtarg.place>1 AND rother.place < rtarg.place)) 
     GROUP BY fixture.id 
     ORDER BY `fixture`.`played` DESC 
     LIMIT 1 
) AS recent; 

沒有指定每個燈具兩個以上球隊的結果格式,因此可能需要進一步調整。

+0

我喜歡這種方法,但不幸的是,它不允許每個燈具有兩個以上球隊的情況。除非我誤解了? – 2010-03-17 05:59:48

+0

你已經明白了。我會很快更新我的答案,併爲每個燈具的兩個以上的球隊提供另一個查詢。 – outis 2010-03-17 23:12:28

+0

非常感謝您的協助! – 2010-03-22 22:21:55