我正在尝试编写一个存储过程,它将根据下面的规则为每条记录返回两个计算值,但我还没弄清楚如何构建SQL以使其发生。我正在使用SQL Server 2008。
首先,相关表格以及与问题相关的字段。
ProductionRuns
RunID (key, and RunID is given to the stored proc as its parameter)
ContainerName
ProductName
TemplateID
TemplateMeasurements
MeasurementTypeID
TemplateID
SimpleBounds
MeasurementTypeID
TemplateID
UpperBound
LowerBound
ContainerBounds
MeasurementTypeID
TemplateID
UpperBound
LowerBound
ContainerName
ProductBounds
MeasurementTypeID
TemplateID
UpperBound
LowerBound
ProductName
这就是我想要回归的。我想为每个TemplateMeasurements记录返回一个计算的上限和下限值,该记录具有与具有提供的runID的ProductionRuns记录匹配的TemplateID。
计算出的上限和下限基本上得到了由于简单,容器和产品界限而可以获得的最严格的界限,如果它们符合条件的话。
如果存在具有正确MeasurementTypeID和TemplateID的SimpleBounds记录,那么它将成为特定MeasurementTypeID和TemplateMeasurements记录的合格边界之一。
要使ContainerBound记录符合条件,TemplateID和MeasurementTypeID必须匹配,但ContainerName必须与ProductionRuns记录中的ContainerName值匹配。同样对于ProductBounds,同样如此,但对于ProductName。
对于特定的MeasurementTypeID,取所有限定边界,并找到最小上限,这将是要返回的计算上限。找到限定符的最大下界,这将是返回的下界。
我不知道如何组合SQL来做到这一点。
此外,如果三个绑定表中没有一个符合特定MeasurementTypeID的条件,则可以返回null。
我的想法是某种左外连接,但我不知道如何将其扩展到三个表中,这些表在结果中都可能为空。
感谢您的帮助。
答案 0 :(得分:1)
我现在没有时间对此进行测试,但希望这会让你非常接近:
SELECT
PR.RunID,
PR.TemplateID,
CASE
WHEN MAX(SB.LowerBound) > MAX(CB.LowerBound) AND
MAX(SB.LowerBound) > MAX(PB.LowerBound) THEN MAX(SB.LowerBound)
WHEN MAX(CB.LowerBound) > MAX(PB.LowerBound) THEN MAX(CB.LowerBound)
ELSE MAX(PB.LowerBound)
END AS LowerBound,
CASE
WHEN MIN(SB.UpperBound) < MIN(CB. UpperBound) AND
MIN(SB. UpperBound) < MIN(PB. UpperBound) THEN MIN(SB. UpperBound)
WHEN MIN(CB. UpperBound) < MIN(PB. UpperBound) THEN MIN(CB. UpperBound)
ELSE MIN(PB. UpperBound)
END
FROM
ProductionRuns PR
INNER JOIN TemplateMeasurements TM ON
TM.TemplateID = PR.TemplateID
LEFT OUTER JOIN SimpleBounds SB ON
SB.TemplateID = PR.TemplateID AND
SB.MeasurementTypeID = TM.MeasurementTypeID
LEFT OUTER JOIN ContainerBounds CB ON
CB.TemplateID = PR.TemplateID AND
CB.MeasurementTypeID = TM.MeasurementTypeID AND
CB.ContainerName = PR.ContainerName
LEFT OUTER JOIN ProductBounds PB ON
PB.TemplateID = PR.TemplateID AND
PB.MeasurementTypeID = TM.MeasurementTypeID AND
PB.ProductName = PR.ProductName
GROUP BY
PR.RunID,
PR.TemplateID
答案 1 :(得分:1)
不要忘记Tom H.的答案,但你也可以考虑用工会而不是连接来解决这个问题,以帮助分割不同的上/下规则。这取决于您认为查询将来需要改变的方式(如果有的话)。
查询最终看起来更干净,特别是没有所有CASE规则,但在TemplateMeasurement行不存在的情况下可能没那么有用。
SELECT RunID, TemplateID, MIN(UpperBound), MAX(LowerBound)
FROM
(SELECT PR.RunID, SB.TemplateID, SB.UpperBound, SB.LowerBound
FROM SimpleBounds SB
INNER JOIN TemplateMeasurements TM
ON SB.TemplateID = TM.TemplateID
AND SB.MeasurementTypeID = TM.MeasurementTypeID
INNER JOIN ProductionRuns PR
ON TM.TemplateID = PR.TemplateID)
UNION
(SELECT PR.RunID, CB.TemplateID, CB.UpperBound, CB.LowerBound
FROM ContainerBounds CB
INNER JOIN TemplateMeasurements TM
ON CB.TemplateID = TM.TemplateID
AND CB.MeasurementTypeID = TM.MeasurementTypeID
INNER JOIN ProductionRuns PR
ON TM.TemplateID = PR.TemplateID
AND CB.ContainerName = PR.ContainerName)
UNION
(SELECT PR.RunID, PB.TemplateID, PB.UpperBound, PB.LowerBound
FROM ProductBounds PB
INNER JOIN TemplateMeasurements TM
ON PB.TemplateID = TM.TemplateID
AND PB.MeasurementTypeID = TM.MeasurementTypeID
INNER JOIN ProductionRuns PR
ON TM.TemplateID = PR.TemplateID
AND PB.ProductName = PR.ProductName)
GROUP BY RunID, TemplateID
答案 2 :(得分:1)
你已经得到了其他应该有效的答案,但在我看来,这种类型的UNIONed内部查询可以产生最清晰,最易维护的方式将水平层次结构折叠成垂直层次结构,这基本上就是你的问题:
SELECT MIN(iq.upperbound), MAX(iq.lowerbound)
FROM TemplateMeasurements tm
INNER JOIN ProductionRuns pr ON tm.TemplateID = pr.TemplateID
LEFT JOIN
(
SELECT sb.UpperBound, sb.LowerBound, sb.MeasurementTypeID, '' as Name, 'sb' as Type, sb.TemplateID
FROM SimpleBounds sb
UNION ALL
SELECT cb.UpperBound, cb.LowerBound, cb.MeasurementTypeID, cb.ContainerName as Name, 'cb' as Type, cb.TemplateID
FROM ContainerBounds cb
UNION ALL
SELECT pb.UpperBound, pb.LowerBound, pb.MeasurementTypeID, pb.ProductName as Name, 'pb' as Type, pb.TemplateID
FROM ProductBounds pb
) iq ON iq.MeasurementTypeID = tm.MeasurementTypeID
AND iq.TemplateID = tm.TemplateID
AND iq.Name =
CASE iq.Type
WHEN 'sb' THEN iq.Name
WHEN 'cb' THEN pr.ContainerName
WHEN 'pb' THEN pr.ProductName
END
WHERE pr.RunID = @runid
GROUP BY tm.TemplateID, tm.MeasurementTypeID
答案 3 :(得分:0)
感谢您带领我朝着正确的方向前进。在我调整它之前,我不得不摆弄这个问题一段时间,但它现在很有效。
我的最终代码和结果:
ALTER PROCEDURE [dbo].[GetBounds]
@runID int
AS
BEGIN
SET NOCOUNT ON;
DECLARE @templateID int
SET @templateID = (SELECT TOP(1) TemplateID
FROM ProductionRuns WHERE RunID = @runID);
SELECT TM.MeasurementTypeID,
CASE
WHEN MIN(SB.UpperBound) < MIN(PB.UpperBound)
AND MIN(SB.UpperBound) < MIN(CB.UpperBound) THEN MIN(SB.UpperBound)
WHEN MIN(PB.UpperBound) < MIN(SB.UpperBound)
AND MIN(PB.UpperBound) < MIN(CB.UpperBound) THEN MIN(PB.UpperBound)
WHEN MIN(CB.UpperBound) < MIN(SB.UpperBound)
AND MIN(CB.UpperBound) < MIN(PB.UpperBound) THEN MIN(CB.UpperBound)
ELSE MIN(SB.UpperBound)
END AS 'UpperBound',
CASE
WHEN MAX(SB.LowerBound) > MAX(PB.LowerBound)
AND MAX(SB.LowerBound) > MAX(CB.LowerBound) THEN MAX(SB.LowerBound)
WHEN MAX(PB.LowerBound) > MAX(SB.LowerBound)
AND MAX(PB.LowerBound) > MAX(CB.LowerBound) THEN MAX(PB.LowerBound)
WHEN MAX(CB.LowerBound) > MAX(SB.LowerBound)
AND MAX(CB.LowerBound) > MAX(PB.LowerBound) THEN MAX(CB.LowerBound)
ELSE MAX(SB.LowerBound)
END AS 'LowerBound'
FROM
ProductionRuns PR
INNER JOIN TemplateMeasurements TM ON
TM.TemplateID = PR.TemplateID
LEFT OUTER JOIN SimpleBounds SB ON
SB.TemplateID = PR.TemplateID AND
SB.MeasurementTypeID = TM.MeasurementTypeID
LEFT OUTER JOIN ContainerBounds CB ON
CB.TemplateID = PR.TemplateID AND
CB.MeasurementTypeID = TM.MeasurementTypeID AND
CB.ContainerName = PR.ContainerName
LEFT OUTER JOIN ProductBounds PB ON
PB.TemplateID = PR.TemplateID AND
PB.MeasurementTypeID = TM.MeasurementTypeID AND
PB.ProductName = PR.ProductName
WHERE TM.TemplateID = @templateID
GROUP BY
TM.MeasurementTypeID
END
特定案例的部分结果,RunID = 3249(TemplateID = 2)
MeasurementTypeID UpperBound LowerBound
2 NULL NULL
11 4 2.5
18 30 1
20 40 10
33 99 0
36 200 140
42 120 32
...