Левое внешнее объединение в SQL Server 2012 LocalDB не работает?

Используя SQL Server 2012 (LocalDB), у меня есть три таблицы:

BESEXT.COMPUTER
BESEXT.ANALYSIS_PROPERTY
BESEXT.ANALYSIS_PROPERTY_RESULT

Это содержит следующую информацию:

  • BESEXT.COMPUTER: сопоставление между идентификаторами компьютеров и именами компьютеров
  • BESEXT.ANALYSIS_PROPERTY: список свойств, которые могут быть сопоставлены с компьютером
  • BESEXT.ANALYSIS_PROPERTY_RESULT: список значений свойств для компьютера

Сначала я выполняю следующий запрос:

SELECT
    AR.ComputerID,
    AP.Name,
    AR.Value
FROM BESEXT.ANALYSIS_PROPERTY_RESULT AR
JOIN BESEXT.ANALYSIS_PROPERTY AP ON AP.ID = AR.PropertyID
    AND AP.ID IN (1672, 1673, 1674)
ORDER BY AR.ComputerID, AP.Name

Что дает следующий результат:

ComputerID  Name                Value
----------  ----                -----
595640      DisplayName         Windows 8.1 x64 - Mobile Device Image - v3.2 
595640      SequenceName        Windows 8.1 x64 - Mobile Device Image
595640      SequenceVersion     3.2
631459      DisplayName         Windows 8.1 x64 - Mobile Device Image - v3.2 
631459      SequenceName        Windows 8.1 x64 - Mobile Device Image
631459      SequenceVersion     3.2

В BESEXT.COMPUTER у меня есть следующие значения:

ID  ComputerID  ComputerName
--  ----------  ------------
1   595640      PO121203866
2   631459      PO121201739
3   1101805     PO121201100

Я хочу выполнить левое внешнее объединение всех моих компьютерных объектов при первом выборе, чтобы я знал, для каких компьютеров у меня нет значения.

Итак, сначала я делаю простое внутреннее соединение с предыдущим выбором:

SELECT
    C.ComputerName,
    R.ComputerID,
    R.Name,
    R.Value
FROM (
    SELECT
        AR.ComputerID,
        AP.Name,
        AR.Value
    FROM BESEXT.ANALYSIS_PROPERTY_RESULT AR
    JOIN BESEXT.ANALYSIS_PROPERTY AP ON AP.ID = AR.PropertyID
        AND AP.ID IN (1672, 1673, 1674)
) R
JOIN BESEXT.COMPUTER C ON C.ComputerID = R.ComputerID
ORDER BY R.ComputerID, R.Name

Что, как и ожидалось, дает следующий набор результатов:

ComputerName    ComputerID  Name            Value
------------    ----------  ----            -----
PO121203866     595640      DisplayName     Windows 8.1 x64 - Mobile Device Image - v3.2 
PO121203866     595640      SequenceName    Windows 8.1 x64 - Mobile Device Image
PO121203866     595640      SequenceVersion 3.2
PO121201739     631459      DisplayName     Windows 8.1 x64 - Mobile Device Image - v3.2 
PO121201739     631459      SequenceName    Windows 8.1 x64 - Mobile Device Image
PO121201739     631459      SequenceVersion 3.2

Теперь, для грандиозного финала, давайте сделаем LEFT OUTER JOIN:

SELECT
    C.ComputerName,
    R.ComputerID,
    R.Name,
    R.Value
FROM (
    SELECT
        AR.ComputerID,
        AP.Name,
        AR.Value
    FROM BESEXT.ANALYSIS_PROPERTY_RESULT AR
    JOIN BESEXT.ANALYSIS_PROPERTY AP ON AP.ID = AR.PropertyID
        AND AP.ID IN (1672, 1673, 1674)
) R
-- LEFT OUTER JOIN ADDED HERE! 
LEFT OUTER JOIN BESEXT.COMPUTER C ON C.ComputerID = R.ComputerID
ORDER BY R.ComputerID, R.Name

Это дает тот же набор результатов, что и при внутреннем соединении!

Это не то, что я ищу, и это совсем не то, что я ожидал. Сейчас уже довольно поздно, и я в основном делаю какую-то работу из-за бессонницы, но я думаю, что это примерно такой же простой пример внешнего соединения, как это возможно, не так ли? Результат, которого я хочу достичь с помощью внешнего соединения, таков:

ComputerName    ComputerID  Name            Value
PO121203866     595640      DisplayName     Windows 8.1 x64 - Mobile Device Image - v3.2 
PO121203866     595640      SequenceName    Windows 8.1 x64 - Mobile Device Image
PO121203866     595640      SequenceVersion 3.2
PO121201739     631459      DisplayName     Windows 8.1 x64 - Mobile Device Image - v3.2 
PO121201739     631459      SequenceName    Windows 8.1 x64 - Mobile Device Image
PO121201739     631459      SequenceVersion 3.2
PO121201100     NULL        NULL            NULL
PO121201100     NULL        NULL            NULL
PO121201100     NULL        NULL            NULL

PS: Если честно, результат, который я ищу, больше похож на этот, но я чувствую, что это был бы совсем другой вопрос:

ComputerName    Name            Value
------------    ----            -----
PO121203866     DisplayName     Windows 8.1 x64 - Mobile Device Image - v3.2 
PO121203866     SequenceName    Windows 8.1 x64 - Mobile Device Image
PO121203866     SequenceVersion 3.2
PO121201739     DisplayName     Windows 8.1 x64 - Mobile Device Image - v3.2 
PO121201739     SequenceName    Windows 8.1 x64 - Mobile Device Image
PO121201739     SequenceVersion 3.2
PO121201100     DisplayName     NULL
PO121201100     SequenceName    NULL
PO121201100     SequenceVersion NULL

3 ответа

Решение

Запрос, который вы ищете, может быть написан просто так:

SELECT ComputerName, A.ComputerID, Name, Value FROM BESEXT.COMPUTER A
CROSS JOIN (SELECT * FROM BESEXT.ANALYSIS_PROPERTY WHERE ID BETWEEN 1672 AND 1674) B
LEFT JOIN BESEXT.ANALYSIS_PROPERTY_RESULT C ON A.ComputerId = C.ComputerId AND B.ID = C.PropertyId
ORDER BY ComputerId, Name

Начните с получения всех комбинаций компьютер-свойства, которые вас интересуют:

SELECT * FROM BESEXT.COMPUTER A
CROSS JOIN (SELECT * FROM BESEXT.ANALYSIS_PROPERTY WHERE ID BETWEEN 1672 AND 1674) B

Это дает результаты:

ID  ComputerId  ComputerName  ID    Name
--  ----------  ------------  --    ----
1   595640      PO121203866   1672  DisplayName
2   631459      PO121201739   1672  DisplayName
3   1101805     PO121201100   1672  DisplayName
1   595640      PO121203866   1673  SequenceName
2   631459      PO121201739   1673  SequenceName
3   1101805     PO121201100   1673  SequenceName
1   595640      PO121203866   1674  SequenceVersion
2   631459      PO121201739   1674  SequenceVersion
3   1101805     PO121201100   1674  SequenceVersion

Оттуда вы просто выполняете левое соединение BESEXT.ANALYSIS_PROPERTY_RESULT чтобы получить ваши ценности, и вы включаете ORDER BY пункт, чтобы отсортировать его.

Вы можете сделать это, используя перекрестное соединение, чтобы настроить свойства для всех компьютеров, а затем левое соединение, чтобы подключиться к фактическим значениям свойств для тех компьютеров, для которых установлены значения:

SELECT * FROM (
    SELECT
       C.ComputerName,
       C.ComputerID,
       AP.Name,
       AP.ID
    FROM BESEXT.COMPUTER C
    CROSS JOIN BESEXT.ANALYSIS_PROPERTY AP
    WHERE AP.ID IN (1672, 1673, 1674)
) AP
LEFT JOIN BESEXT.ANALYSIS_PROPERTY_RESULT AR  
ON AP.ComputerID = AR.ComputerID AND AP.ID = AR.PropertyID
ORDER BY AP.ComputerName DESC, AP.Name

Как LOJ это будет так?

SELECT
    R.ComputerName,
    C.ComputerID,
    C.Name,
    C.Value
FROM BESEXT.COMPUTER R
-- LEFT OUTER JOIN ADDED HERE! 
LEFT OUTER JOIN 
(
    SELECT
        AR.ComputerID,
        AP.Name,
        AR.Value
    FROM BESEXT.ANALYSIS_PROPERTY_RESULT AR
    JOIN BESEXT.ANALYSIS_PROPERTY AP ON AP.ID = AR.PropertyID
        AND AP.ID IN (1672, 1673, 1674)
) C 
  ON C.ComputerID = R.ComputerID
ORDER BY C.ComputerID, C.Name
Другие вопросы по тегам