2017-01-03 44 views
2

任何人都達到SQL挑戰?因爲我迄今爲止所做的所有努力幾乎不足以簡化問題並將其置於一個問題中......從多個表中選擇與交叉引用和自引用[brain cracker]

在這裏。在下面的例子中,我們需要包括:

  • 一個國家(薪或無薪)所有支付航班
  • 機票如果一個人做出了另一架飛機到付費城市在該國

這已經很棘手,但還有更多。

  • 如果一個人對飛行沒有報名費一個城市,但它位於一個 國家,確實有一定的費用,該航班仍然被認爲是支付 ,必須包括在內。

enter image description here 編輯:我增加航班110,這將有助於揭示不必要的添加免費fligts。

下面是結果集將要來的SQL查詢出來:

+--------------------------------------------------------------+ 
| Desired result set           | 
+--------------------------------------------------------------+ 
| FlightNumber | ID | Name | LocationID | location.Name  | 
+--------------------------------------------------------------+ 
| 102   | 2 | Tom | 500  | NL - NoFee   | -> because Tom has a paid flight to Amsterdam 
| 103   | 2 | Tom | 501  | Amsterdam (NL) - Fee | -> because Amsterdam is a paid location 
| 105   | 4 | Bob | 501  | Amsterdam (NL) - Fee | -> because Amsterdam is a paid location 
| 107   | 6 | Bill | 503  | ITA - Fee   | -> because ITA is a paid location 
| 108   | 7 | Ryan | 503  | ITA - Fee   | -> because ITA is a paid location 
| 109   | 7 | Ryan | 505  | Venice (ITA) - NoFee | -> because Venice is located inside ITA 
+--------------------------------------------------------------+ 

有誰知道如何得到這個甜蜜的結果與SQL設置?

一個良好的開端:

SELECT flights.FlightNumber, people.ID, people.Name, flights.LocationID, locations.Name 
FROM flights 
INNER JOIN people ON (people.ID = flights.ID) 
INNER JOIN locations ON (locations.LocationID = flights.LocationID) 

創建/插入

CREATE TABLE `people` (
    `ID` INT NOT NULL, 
    `Name` VARCHAR(45) NULL, 
    PRIMARY KEY (`ID`)); 

CREATE TABLE `locations` (
    `LocationID` INT NOT NULL, 
    `Name` VARCHAR(45) NULL, 
    `EntryFee` TINYINT(1) NULL, 
    `ParentLocationID` INT NULL, 
    PRIMARY KEY (`LocationID`)); 

CREATE TABLE `flights` (
    `FlightNumber` INT NOT NULL, 
    `ID` INT NULL, 
    `LocationID` INT NULL, 
    PRIMARY KEY (`FlightNumber`) , 
    INDEX `fk_purchases_buyers_idx` (`LocationID` ASC) , 
    INDEX `fk_flights_people1_idx` (`ID` ASC) , 
    CONSTRAINT `fk_purchases_buyers` 
    FOREIGN KEY (`LocationID`) 
    REFERENCES `locations` (`LocationID`) 
    ON DELETE NO ACTION 
    ON UPDATE NO ACTION, 
    CONSTRAINT `fk_flights_people1` 
    FOREIGN KEY (`ID`) 
    REFERENCES `people` (`ID`) 
    ON DELETE NO ACTION 
    ON UPDATE NO ACTION); 

INSERT INTO `people` (`ID`, `Name`) VALUES 
(1, 'John'), 
(2, 'Tom'), 
(3, 'Kate'), 
(4, 'Bob'), 
(5, 'Mike'), 
(6, 'Bill'), 
(7, 'Ryan'); 

INSERT INTO `locations` (`LocationID`, `Name`, `EntryFee`, `ParentLocationID`) VALUES 
(500, 'NL - NoFee', 0, NULL), 
(501, 'Amsterdam (NL) - Fee', 1, 500), 
(502, 'Rotterdam (NL) - NoFee', 0, 500), 
(503, 'ITA - Fee', 1, NULL), 
(504, 'Rome (ITA) - Fee', 1, 503), 
(505, 'Venice (ITA) - NoFee', 0, 503); 

INSERT INTO `flights` VALUES 
(100, 1, 500), 
(101, 1, 502), 
(102, 2, 500), 
(103, 2, 501), 
(104, 3, 500), 
(105, 4, 501), 
(106, 5, 502), 
(107, 6, 503), 
(108, 7, 503), 
(109, 7, 505), 
(110, 6, 502); 

不重要注:我知道這個例子是不是在存儲國家意識完全合乎邏輯和在同一張桌子上的城市,有一個國家和一個城市的航班記錄。但這只是一個例子。至少它比t1.col1更具可讀性。

+0

所以你的問題是如何走向位置的父層次結構? –

+1

我給你一個提示:第二個條件包含第一個條件。 –

+0

@RC。在這種情況下,層次結構相當平坦(最大1層深度),這完全可以通過「國家/地區>城市」示例反映出來。城市擁有父母國家,但城市內或城市內不能有城市。問題更多的是選擇付費航班和只有相關的免費航班。 –

回答

3

下面應該工作:

SELECT F.FlightNumber, P.ID, P.Name, F.LocationID, LOC.Name AS Loc_Name 
FROM flights F 
INNER JOIN people P ON P.ID = F.ID 
INNER JOIN (SELECT L1.LocationID, L1.`Name`, L1.`ParentLocationID` 
      FROM locations L1 
      LEFT JOIN locations L2 ON L1.`ParentLocationID` = L2.LocationID 
      WHERE L1.`EntryFee` = 1 OR L2.`EntryFee` = 1) AS LOC ON LOC.LocationID = F.LocationID 
UNION 
SELECT F.FlightNumber, PAID_FL.ID, PAID_FL.Name, F.LocationID, PAID_FL.Loc_Name 
FROM flights F 
INNER JOIN (SELECT F.FlightNumber, P.ID, P.Name, LOC.Name AS Loc_Name,LOC.`ParentLocationID` AS LocationID 
      FROM flights F 
      INNER JOIN people P ON P.ID = F.ID 
      INNER JOIN (SELECT L1.LocationID, L1.`ParentLocationID`, L2.`Name` 
         FROM locations L1 
         LEFT JOIN locations L2 ON L1.`ParentLocationID` = L2.LocationID 
         WHERE L1.`EntryFee` = 1 OR L2.`EntryFee` = 1) AS LOC ON LOC.LocationID = F.LocationID) PAID_FL ON F.ID = PAID_FL.ID AND F.LocationID = PAID_FL.LocationID 
+0

CptMisery:您的查詢也可以使用,除非(某個國家/地區(付費或不是),如果某人已經乘坐另一班航班前往該國的付費城市)。在此您的查詢將返回航班到該國家的非付費城市。 – meet

+0

你能解釋爲什麼CptMisery的方法不會返回這些嗎?我承認我在描述中提供的數據集可能不包含所有可能的關係組合,但對於這個數據集,您的兩種方法都會返回相同的行。除你的訂單因UNION不同而有所不同... –

+0

INSERT INTO'flights' VALUES(110,5,501)這樣做,你就會知道 – meet

0
SELECT x.* 
    , COALESCE(y.entryfee,x.entryfee,0) fee 
    FROM locations x 
    LEFT 
    JOIN locations y 
    ON y.parentlocationid = x.locationid; 
+0

這只是返回所有位置。我不明白。這有什麼幫助? –

+0

對於該位置路徑的任何部分都有入口點的所有位置(除非它不是因爲我稍微塞滿了查詢)而返回1 – Strawberry

2

我沒有做任何測試,但我認爲這將工作:

SELECT F.FlightNumber, P.ID, P.Name, L.LocationID, L.Name 
FROM flights F 
INNER JOIN people P ON P.ID = F.ID 
INNER JOIN locations L ON L.LocationID = F.LocationID 
WHERE P.ID IN (SELECT F.ID FROM flights F INNER JOIN locations L ON L.LocationID = F.LocationID WHERE L.EntryFee = 1) 

See it at SQLFiddle.com.

+0

某處出現錯誤。在第5行,MySQL除了'near'之外沒有提供太多調試信息。你能檢查一下嗎?還有sqlfiddle.com tot測試現場,但它今天沒有工作(昨天它沒有):/ –

+0

以前沒有用過sqlfiddle。所以我不確定如何分享我在那裏做的事情,但是這個查詢可以使用上面的數據庫模式。編輯:我也改變了我的查詢中的一些列的大小寫。 – CptMisery

+0

@ Alph.Dev那個特定的錯誤通常意味着不同數量的開合圓括號 – Strawberry