SQL FIDDLE (省略astAssets
以降低复杂性)
我需要获取资产的某些维护任务的列表,以及它们各自的子任务和备件数量。
任务链接到资产,子任务和备件都在单独的表中,这些表链接到具有ID的任务。
因此,以下两个查询将分别获取所有资产的所有子任务和任务
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
。
问题在于子任务和备用任务之间没有链接,即使它们有时是明确相关的(如上例所示)。
使事情更复杂:
即使子任务,备件或两者都不存在,我也想列出库存项目代码,任务,子任务描述和备件数量。以下查询不起作用,因为它不能将备件链接到子任务。结果,一个库存项目可能针对同一任务以不同数量多次列出,因为它从该任务中所有备件中获取数量。结果,您可能会错误地为一个库存项目获得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的屏幕抓图,并显示了问题。顶层表是各自任务(行1)中所有备件(行2)和相应数量(行3)的列表。第二个表是使用上面的查询构造的。如您所知,它将显示备件数量错误的库存物料代码。它仅显示该特定任务和库存的所有可能组合。
答案 0 :(得分:1)
您真的应该为sqlfiddle中给出的示例数据提供一些“预期输出”。如果我说很容易理解您的需求,那我会撒谎,但我仍然不确定我是否正确。
因此,基本上,此方法的工作方式是尝试从任务描述(subTasks CTE)中提取零件ID,然后尝试从那里匹配备用记录(SubTasksWithMatchingSpares CTE)。不能与子任务匹配的给定任务的所有剩余备件被单独列出(WithoutSubtasks 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