2012-05-18 31 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

相关问题