Использование join для включения нулевых значений в ту же таблицу

#sql #sql-server

#sql #sql-сервер

Вопрос:

Ниже приведена моя структура таблицы.

  1. AttributeMaster — эта таблица является главной таблицей атрибутов, которая будет доступна для каждого запроса.
AttrMasterId attrName
1 Статьи расходов
2 Бизнес-причина
  1. AttributeValue — когда пользователь заполняет данные из таблицы, если столбец пуст, мы не сохраняем его значение в базе данных.

Для каждого запроса существует несколько строк (TaskId). Каждая задача должна иметь атрибуты из мастера атрибутов. Теперь, если у пользователя нет атрибута, мы не сохраняем его в базе данных.

AttrValId RequestID Идентификатор задачи AttrMasterId attrValue RecordStatus
1 200 1 1 Мебель A
2 200 2 1 Infra A
3 200 2 2 Перемещение A

В приведенном выше сценарии для запроса 200 для идентификатора задачи — 1 у меня есть значение только для одного атрибута. Для идентификатора задачи — 2 у меня заполнены оба атрибута.

Результат запроса должен дать мне 4 строки, по 2 для каждого идентификатора задачи, с нулевыми заполнителями в столбце attrValue.

 select * from AttributeMaster cam 
left join AttributeValue cav on cam.AttrMasterId = cav.AttrMasterId 
and cav.requestId = 36498 and cav.recordStatus = 'A'
right outer join (select distinct AttrMasterId from attrValue cav1 where cav1.requestId = 36498  ) ctI on cti.AttrMasterId = cav.AttrMasterId;
 

До сих пор я пробовал разные объединения, пытался самостоятельно объединить таблицу значений атрибутов, как указано выше, по-прежнему никаких результатов для заполнения пустых строк.

Любая помощь или указания будут оценены. Спасибо.

Редактировать 1: ожидаемый результат выглядит следующим образом:

RequestID Идентификатор задачи AttrMasterId attrValue RecordStatus
200 1 1 Мебель A
200 1 2 NULL NULL
200 2 1 Infra A
200 2 2 Перемещение A

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

1. Добавление ожидаемого результата помогло бы!

2. @Arun добавил ожидаемый результат

Ответ №1:

Рабочая скрипка для SQL Server

Поскольку действительно должна быть таблица задач, я добавил ее в качестве термина CTE в первом решении. Вторая форма просто использует ваши существующие таблицы напрямую, с тем же результатом.

 WITH Task (TaskId) AS (
        SELECT DISTINCT TaskId FROM AttributeValue
     )
   , pairs (TaskId, AttrMasterId) AS (
        SELECT Task.TaskId, AttributeMaster.AttrMasterId
          FROM AttributeMaster CROSS JOIN Task
     )
SELECT pairs.*
     , AttributeMaster.*
     , cav.*
  FROM pairs
  JOIN AttributeMaster
    ON pairs.AttrMasterId = AttributeMaster.AttrMasterId
  LEFT JOIN AttributeValue AS cav
    ON pairs.AttrMasterId = cav.AttrMasterId AND pairs.TaskId = cav.TaskId
   AND cav.requestId = 200 AND cav.recordStatus = 'A'
 ORDER BY pairs.TaskId, pairs.AttrMasterId
;
 
  -------- -------------- -------------- ----------------- ----------- ----------- -------- -------------- ------------ -------------- 
| TaskId | AttrMasterId | AttrMasterId | AttrName        | AttrValId | RequestId | TaskId | AttrMasterId | AttrValue  | RecordStatus |
 -------- -------------- -------------- ----------------- ----------- ----------- -------- -------------- ------------ -------------- 
|      1 |            1 |            1 | Expense Items   |         1 |       200 |      1 |            1 | Furniture  | A            |
|      1 |            2 |            2 | Business Reason |      NULL |      NULL |   NULL |         NULL | NULL       | NULL         |
|      2 |            1 |            1 | Expense Items   |         2 |       200 |      2 |            1 | Infra      | A            |
|      2 |            2 |            2 | Business Reason |         3 |       200 |      2 |            2 | Relocation | A            |
 -------- -------------- -------------- ----------------- ----------- ----------- -------- -------------- ------------ -------------- 
 

Вторая форма без добавленного Task термина CTE…

 WITH pairs AS (
        SELECT DISTINCT AttributeValue.TaskId, AttributeMaster.AttrMasterId
          FROM AttributeMaster CROSS JOIN AttributeValue
     )
SELECT pairs.*
     , AttributeMaster.*
     , cav.*
  FROM pairs
  JOIN AttributeMaster
    ON pairs.AttrMasterId = AttributeMaster.AttrMasterId
  LEFT JOIN AttributeValue AS cav
    ON pairs.AttrMasterId = cav.AttrMasterId AND pairs.TaskId = cav.TaskId
   AND cav.requestId = 200 AND cav.recordStatus = 'A'
 ORDER BY pairs.TaskId, pairs.AttrMasterId
;
 

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

1. Спасибо, приятель. Это работает. Я был настолько сосредоточен на самостоятельном соединении, что забыл об аспекте перекрестного соединения. работает как шарм.

2. Вы могли бы сделать это с одним соединением меньше, если хотите, см. Мой ответ

3. @GuidoG Это правильно. Я включил дополнительное соединение только для отображения attrName в результате, что не было обязательным требованием, и я не хотел включать имя в исходное перекрестное соединение. Нам нужны были только пары (TaskId, AttrMasterId) перед внешним соединением.

Ответ №2:

Вот еще одно решение, которое не требует CTE.
В нем также используется ответ TaskID like @jon-armstrong

 declare @AttributeMaster table (MasterID int, Name varchar(50))
declare @AttributeValues table (ValueID int, RequestID int, TaskID int, MasterID int, Value varchar(50), Status varchar(1))

insert into @AttributeMaster (MasterID, Name)
values (1, 'Expense'), (2, 'Business')

insert into @AttributeValues (ValueID, RequestID, TaskID, MasterID, Value, Status)
values (1, 200, 1, 1, 'Furniture', 'A'),
       (2, 200, 2, 1, 'Infra', 'A'),
       (3, 200, 2, 2, 'Relocation', 'A')


select t.RequestID, t.TaskID, t.MasterID, v.Value, v.Status, t.Name
from   ( select distinct m.MasterID, v.TaskID, v.RequestID, m.Name 
         from   @AttributeMaster m cross join @AttributeValues v
       ) t
  left join @AttributeValues v on v.MasterID = t.MasterID and v.TaskID = t.TaskID 
                              and v.RequestID = 200 and v.Status = 'A'

order by t.TaskID, t.MasterID
 

результат

 RequestID   TaskID  MasterID    Value       Status  Name
200         1       1           Furniture   A       Expense
200         1       2           NULL        NULL    Business
200         2       1           Infra       A       Expense
200         2       2           Relocation  A       Business