1

假设我有三个表:

  • Cars (CarID) 包含 10 个不同的汽车行。
  • SafetyTests (TestID, TestName) 包含 20 个不同的安全测试行。
  • TestResults(ID、TestID、CarID、TestValue)包含 0 到 200 个安全测试行之间的数字。

在安全测试表中,它包含对 Cars 表中的 10 辆汽车执行的每个安全测试的结果。最多有 20 个安全测试——这显然是从 SafetyTests 表上的 select 语句中获得的。然而,这 10 辆汽车中的一些已经完成了所有 20 次测试,而其他汽车只进行了 5 次。

我想生成一个 10 x 20 矩阵,它将显示每辆车 20 个结果(即使他们没有 20 个安全测试结果)。如果尚未在汽车上执行测试,它只会显示测试名称,但值为零(或 null)。

我认为这将是 SafetyTests 表上的 SELECT (以获取不同的测试 ID 列表)和 LEFT JOIN 到 Cars 和 TestResults 之间的 JOIN 组合上,但问题是这会返回 NULL 的 CAR ID 缺少测试,因为Car 表没有匹配项。

4

2 回答 2

4

您可以从汽车交叉连接到安全测试 - 然后左连接到 TestResults - 交叉连接确保您获得 10 x 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

这是交叉连接的工作

按照某人的建议做了一个 sqlfiddle :) 那个网站真的很好

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

于 2012-05-18T09:00:00.977 回答
3

如果我正确理解了这个问题,您需要一个 10x20 的结果集,如下所示:

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小提琴

于 2012-05-18T09:12:06.517 回答