Соединить две таблицы без правильного идентификатора ссылки - PullRequest
0 голосов
/ 02 апреля 2019

SQL FIDDLE (astAssets опущен, чтобы уменьшить сложность)

Мне нужен список определенных задач обслуживания для актива, вместе с их соответствующимиколичество подзадач и запасных частей.

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

Таким образом, следующие два запроса будут соответственнополучить все подзадачи и задачи из всех активов

Select T.Code, ST.Description From astTasks T
    Join astTaskSubTasks ST ON ST.ParentId = T.Id
    Join astAssets A ON A.Id = T.AssetId

Select T.Code, S.StockItemId From astTasks T
    Join astTaskSpares S ON S.ParentId = T.Id
    Join astAssets A ON A.Id = T.AssetId

Описание записей подзадач содержит код товара.Запасные записи связаны с кодом элемента запаса с помощью StockItemId.

. Я хочу получить список всех задач в активе вместе со всеми подзадачами и запасными частями для этих задач.Подзадачи и запасные части часто (но не всегда) относятся к одним и тем же товарам на складе.Например, задача A содержит подзадачу, в которой указано, что товарная позиция 0990 будет заменяться каждые 12 месяцев, и, следовательно, товарная позиция 0990 была включена в список запасных частей для этой задачи.

Проблема заключается в том, что подзадачи и запасные части не имеют связи между ними, даже если они иногда четко связаны (как в примере выше).

Чтобы усложнить задачу:

  • Задачи страхового запаса содержат запасные части, но не имеют подзадач (ничего не нужно делать)
  • Для некоторых подзадач требуется только запасэлемент, подлежащий визуальной проверке, и, следовательно, нет соответствующих запасных частей
  • Запасные части могут отсутствовать как ошибка пользователя
  • Подзадачи и запасные части отсутствуют в задаче, которая является другой ошибкой пользователя

Я хочу перечислить код товара, задачу, описание подзадачи и количество запасных частей, даже если подзадачи, запасные части или оба отсутствуют. Приведенный ниже запрос не работает, так как он может 't связать запасные части с подзадачами.В результате один запасной элемент может быть указан несколько раз для одной и той же задачи с разными количествами, поскольку он получает количества из всех запасных частей в этой задаче.В результате вы можете ошибочно получить 4 записи для одного товара.

Select Distinct
 CASE WHEN ST.Description IS NULL THEN SI.Code ELSE LTRIM(SUBSTRING(ST.Description, CHARINDEX('x ' , Substring(ST.Description, PATINDEX('%(%[^A-Z]% x %', ST.Description),50) ) +  PATINDEX('%(%[^A-Z]% x %', ST.Description)+1, (CHARINDEX(') - (', ST.Description) - (CHARINDEX('x ' , Substring(ST.Description, PATINDEX('%(%[^A-Z]% x %', ST.Description),50) ) +  PATINDEX('%(%[^A-Z]% x %', ST.Description)))-1)) END
, T.Code
, Left(ST.Description, CHARINDEX(' ',ST.Description, 1))
, CASE WHEN Left(ST.Description, CHARINDEX(' ',ST.Description, 1)) = 'Check' Then 'Check' ELSE CAST(S.Quantity as nvarchar) END
From astTasks T

Join astAssets A ON A.Id = T.AssetId 

Left Join astTaskSubTasks ST ON ST.ParentId = T.Id
Left Join astTaskSpares S ON S.ParentId = T.Id
Left Join stkStockItems SI ON SI.Id = S.StockItemId

Where
A.Code = '2016404991'

На изображении ниже показан скриншот из fiddle и показана проблема.Верхняя таблица - это список всех запчастей (столбец 2) в соответствующих задачах (столбец 1) с соответствующими количествами (столбец 3).Вторая таблица была построена с запросом выше.Как вы можете заметить, он отображает коды запаса с неправильными запасными количествами.Он просто показывает все возможные комбинации для этой конкретной задачи и запаса.

Problem

1 Ответ

1 голос
/ 03 апреля 2019

Вы действительно должны были предоставить некоторые "ожидаемые результаты" для данных примера, приведенных в sqlfiddle.Я бы соврал, если бы сказал, что было легко понять, что вам нужно, и я до сих пор не уверен, что понял все правильно.

Так что в принципе это работает так, что он пытается извлечь частьидентификатор из описания задачи (подзадачи CTE), а затем пытается сопоставить запасную запись оттуда (SubTasksWithMatchingSpares CTE).Все оставшиеся запасные части для данной задачи, которые не могут быть сопоставлены с подзадачей, перечислены отдельно (без подзадач CTE).Затем оба набора результатов объединяются для получения полного списка задач -> подзадача -> запасная + задача -> запасная.

;WITH subTasks AS
(

    SELECT ST.Id
         , ST.ParentId
         , Description
         , SI.Id AS StockItemId         
      FROM astTaskSubTasks ST
     -- Find the space, delimiting the verb from part code, if any
     CROSS
     APPLY (SELECT CHARINDEX(' ', ST.Description) spaceIndex) x1
     -- Extract the part code
     CROSS
     APPLY (SELECT RIGHT(ST.Description, LEN(ST.Description) - x1.spaceIndex) AS PartCode) x2
      -- Related stock item
      LEFT OUTER
      JOIN stkStockItems SI
        ON SI.Code = x2.PartCode
),
-- Match spares against the spare codes extracted from subtask description, if there is one
SubTasksWithMatchingSpares AS
(
SELECT T.Id AS TaskId
     , T.Code AS TaskCode
     , ST.Id AS SubTaskId
     , ST.Description AS SubTaskDescription
     , ST.Id
     , ST.StockItemId AS SpareId
     , TS.Quantity AS SpareQuantity
  FROM astTasks T
  LEFT OUTER
  JOIN subTasks ST 
    ON ST.ParentId = T.Id
  LEFT OUTER
  JOIN astTaskSpares TS
    ON TS.ParentId = T.Id
   AND TS.StockItemId = ST.StockItemId
),
-- Leftover task spares that were not matched against the subtask description
WithoutSubtasks AS
(
SELECT T.Id AS TaskId
     , T.Code AS TaskCode
     , SI.Code AS Code
     , TS.Quantity AS SpareQuantity
  FROM astTasks T 
  LEFT OUTER
  JOIN astTaskSpares TS
    ON TS.ParentId = T.Id
 INNER
  JOIN stkStockItems SI
    ON SI.Id = TS.StockItemId 
   -- check if the subtask successfully matched it
   AND NOT EXISTS (SELECT 1 FROM subTasks checkIfAlreadyMatched
                     WHERE checkIfAlreadyMatched.ParentId = TS.ParentId
                       AND checkIfAlreadyMatched.StockItemId = TS.StockItemId)

),
AllTogether AS
(
-- All tasks will be here, whether subtask matched or not; if it did, it also matched against the spare
SELECT ST.TaskId
     , ST.TaskCode
     , ST.SubTaskId
     , ST.SubTaskDescription
     , SI.Code
     , ST.SpareQuantity
  FROM SubTasksWithMatchingSpares ST
  LEFT OUTER
  JOIN stkStockItems SI
    ON SI.Id = ST.SpareId
 -- check to match tasks without a subtask that have been matched against a spare
 -- to avoid empty records, if such a match exists
 WHERE NOT EXISTS (SELECT 1 
                     FROM WithoutSubtasks withoutST 
                    WHERE withoutST.TaskId = ST.TaskId
                      AND SI.Code IS NULL)


UNION ALL
-- Only tasks that have a spare are here, and the spare was not matched against a subtask
SELECT ST.TaskId
     , ST.TaskCode
     , NULL
     , NULL
     , ST.Code
     , ST.SpareQuantity
  FROM WithoutSubtasks ST
 )
 SELECT * FROM AllTogether
 ORDER BY TaskId

Результаты sqlfiddle

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...