Множественные самосоединения и нулевые значения

#sql #sql-server

#sql #sql-сервер

Вопрос:

Я уверен, что это будет легко исправить, но мы здесь.

У меня есть таблица, которая извлекает данные из контрольного списка, и я хочу создать отчет на основе ответов на несколько вопросов.

Стол накрыт вот так:

 list_id | QuestionID | Question   | Answer
   1    |     11     | Supervisor?| Jack
   1    |     12     |  Crew 1?   | Sam
   1    |     13     |  Crew 2?   | Sally
   1    |     14     |  Crew 3?   | NULL
  

Потенциально существует ‘Crew 3?’, но обычно это null, то же самое с Crew 2, если на то пошло. Теперь я хочу, чтобы Отчет выглядел следующим образом:

 Supervisor | Crew 1 | Crew 2 | Crew 3
  

Но когда я использую левое соединение для самостоятельного соединения с таблицей, я получаю только те результаты, которые включают все три команды, и исключаю все экземпляры, где есть нулевые поля.

Моя текущая попытка:

 SELECT
      sup.Answer AS 'Sup'
      ,C1.Answer AS '1'
      ,C2.Answer AS '2'
      ,C3.Answer AS '3'
  FROM ChecklistDetail AS sup
  LEFT JOIN ChecklistDetail AS C1 
       ON C1.listID =sup.listID

  LEFT JOIN ChecklistDetail AS C2 
       ON C2.listID =sup.listID

  LEFT JOIN ChecklistDetail AS C3 
       ON C3.listID =sup.listID

  WHERE 
  sup.QuestionID = 11
  AND C1.QuestionID = 12
  AND C2.QuestionID = 13
  AND C3.QuestionID = 14
  

Вероятно, это что-то очевидное, но я наткнулся на кирпичную стену, просматривая Google и находя кучу довольно близких ответов, которые не совсем работают. Будем признательны за любую помощь!

Комментарии:

1. О! Мои извинения, первый пост и все такое. Я использую SQL-Server Management Studio.

Ответ №1:

Чтобы ответить на ваш вопрос напрямую, вставьте фильтры идентификаторов вопросов в объединения… Таким образом, проверка выполняется во время объединения, а не после него (когда идентификатор может быть нулевым).

   SELECT
      sup.Answer AS 'Sup'
      ,C1.Answer AS '1'
      ,C2.Answer AS '2'
      ,C3.Answer AS '3'
  FROM ChecklistDetail AS sup
  LEFT JOIN ChecklistDetail AS C1 
       ON C1.listID =sup.listID
       AND C1.QuestionID = 12
  LEFT JOIN ChecklistDetail AS C2 
       ON C2.listID =sup.listID
       AND C2.QuestionID = 13
  LEFT JOIN ChecklistDetail AS C3 
       ON C3.listID =sup.listID
       AND C3.QuestionID = 14
  WHERE 
      sup.QuestionID = 11
  

Однако лучшим способом может быть условное агрегирование…

 SELECT
  ListID,
  MAX(CASE WHEN QuestionID = 11 THEN Answer END)   AS 'sup', 
  MAX(CASE WHEN QuestionID = 12 THEN Answer END)   AS '1', 
  MAX(CASE WHEN QuestionID = 13 THEN Answer END)   AS '2', 
  MAX(CASE WHEN QuestionID = 14 THEN Answer END)   AS '3'
FROM
  ChecklistDetail
WHERE
  QuestionID IN (11,12,13,14)
GROUP BY
  ListID
  

Комментарии:

1. Ааааааннд, это было так просто! Большое вам спасибо! Мне придется изучить условную агрегацию, но пока это, безусловно, сработает.

2. @zacwatkins Теперь я добавил SQL с условной агрегацией (кроме того, загляните в PIVOT, хотя мне это не нравится, и я предпочитаю условную агрегацию, за мои грехи)