2012-05-18 60 views
1

假設我有三個表格:我需要什麼樣的JOIN來執行這種類型的查詢?

  • 汽車(CarID)包含10個明顯的汽車行。
  • SafetyTests(TestID,TestName)包含20個不同的安全測試行。
  • TestResults(ID,TestID,CarID,TestValue)包含一個介於0到200個安全測試行之間的數字。

在安全測試表中,它包含從汽車表中的10輛汽車執行的每項安全測試的結果。最多有20項安全測試 - 顯然是通過SafetyTests表上的select語句獲得的。然而,10輛車中的一些已經進行了全部20次測試,而其他車輛僅進行了20次測試。而其他車輛僅有5輛。我想要生成10 x 20矩陣,每輛車將顯示20個結果(即使他們沒有20次安全測試結果)。如果測試還沒有在車上執行,它只會顯示測試名稱,但值爲零(或空值)。

我認爲這將是SafetyTests表上的SELECT(以獲得不同的測試ID列表)和LEFT JOIN到Cars和TestResults之間的JOIN組合上,但問題是此返回CAR ID爲NULL因爲沒有與Car表匹配,因此缺少測試。

回答

4

可以CROSS JOIN從汽車安全測試 - 然後離開加盟TestResults - 交叉聯接確保您獲得的10×20矩陣,左側加入給你的結果

使用ISNULL或COALESCE更換空在結果集中爲零

例如

SELECT car.name, testresults.testname, isnull(testresults.result, 0) FROM 
cars CROSS JOIN 
safetytests 
LEFT JOIN testresults on safetytests.testid = testresults.testid AND car.id = testresults.carid 

Here's the cross join working

沒過sqlfiddle有人建議:)真正的好該網站

http://sqlfiddle.com/#!3/2bc73/2

+0

砸,絕對的感謝!我不知道有交叉連接這樣的事情。當我在上週看到加入時,我從未在W3Schools頁面上看到過這一點!它有另一個名字,如全聯接等? – mezamorphic

+0

沒有完整連接是不同的連接 - 交叉連接只是行的笛卡爾乘積,不需要任何連接條件(我更新了左連接,因爲它缺少汽車連接來測試結果)。CROSS JOIN總是給出(左邊的行數)*(右邊的行數) – Charleh

+0

在我的db上模擬表格並添加了一個圖像來證明它有效:) – Charleh

3

如果我理解正確的問題,你想一個10×20的結果集是這樣的:

CarID | Test1 | Test2 | .... | Test20 
------------------------------------------------------- 
1  | NULL | Fail | .... | true 
2  | 2  | Pass | .... | false 

爲此,我將利用SQL-Server 2008的PIVOT函數。

WITH Results AS 
( SELECT cars.CarID, 
      TestName, 
      TestValue 
    FROM Cars 
      CROSS JOIN SafetyTests s 
      LEFT JOIN TestResults res 
       ON res.CarID = Cars.CarID 
       AND res.TestID = s.TestID 
) 
SELECT * 
FROM Results 
     PIVOT 
     ( MAX(TestValue) 
      FOR TestName IN ([TesT1], [Test2], [Test3], [Test4]) 
      -- LIST ALL 20 TEST NAMES HERE 
     ) pvt 

這樣做的缺點是,你必須明確地列出所有的測試名稱擺動,否則他們將不會顯示爲列,但它是可以動態地做到這一點。下面的查詢基本上與上面的查詢完全相同,但是我已經動態生成了所有列名的列表並將它們插入到查詢中。

DECLARE @SQL NVARCHAR(MAX) = '' 

SELECT @SQL = @SQL + ',' + QUOTENAME(TestName) 
FROM SafetyTests 

SET @SQL = 'WITH Results AS 
      ( SELECT Cars.CarID, 
         TestName, 
         TestValue 
       FROM Cars 
         CROSS JOIN SafetyTests s 
         LEFT JOIN TestResults res 
          ON res.CarID = Cars.CarID 
          AND res.TestID = s.TestID 
      ) 
      SELECT * 
      FROM Results 
        PIVOT 
        ( MAX(TestValue) 
         FOR TestName IN (' + STUFF(@SQL, 1, 1, '') + ') 
        ) pvt' 

EXECUTE SP_EXECUTESQL @SQL 

SQL Fiddle

+0

不要問它是否是正確的答案,但它是使用STUFF的PIVOT和動態PIVOT的一個很好的例子,所以+1 – Charleh

相關問題