查找 T-SQL 以返回这些值
Posted
技术标签:
【中文标题】查找 T-SQL 以返回这些值【英文标题】:Finding the T-SQL to return these values 【发布时间】:2009-02-25 15:55:08 【问题描述】:我正在尝试编写一个存储过程,它将根据以下规则为每条记录返回两个计算值,但我还没有弄清楚如何构建 SQL 来实现它。我正在使用 SQL Server 2008。
首先,相关的表格和与问题相关的字段。
生产运行
RunID (key, and RunID is given to the stored proc as its parameter)
ContainerName
ProductName
TemplateID
模板测量
MeasurementTypeID
TemplateID
简单边界
MeasurementTypeID
TemplateID
UpperBound
LowerBound
容器边界
MeasurementTypeID
TemplateID
UpperBound
LowerBound
ContainerName
产品边界
MeasurementTypeID
TemplateID
UpperBound
LowerBound
ProductName
这就是我想要返回的。我想为每个 TemplateMeasurements 记录返回一个计算的上限和下限值,该记录与具有提供的 runID 的 ProductionRuns 记录匹配。
计算的上限和下限基本上得到了作为简单、容器和产品边界的结果可以获得的最严格的边界,如果它们符合条件的话。
如果存在具有正确 MeasurementTypeID 和 TemplateID 的 SimpleBounds 记录,则该记录将成为特定 MeasurementTypeID 和 TemplateMeasurements 记录的限定范围之一。
要使 ContainerBound 记录符合条件,TemplateID 和 MeasurementTypeID 必须匹配,而且 ContainerName 必须与 ProductionRuns 记录中的 ContainerName 值匹配。对于 ProductBounds 也是如此,但对于 ProductName。
对于特定的MeasurementTypeID,获取所有限定范围,并找到最小的Upper Bound,这将是要返回的计算的Upper Bound。找到限定符的最大下界,这将是返回的下界。
不过,我不知道如何组合 SQL 来执行此操作。
此外,如果三个绑定表都不符合特定 MeasurementTypeID 的条件,则可能返回 null。
我的想法是某种左外连接,但我不确定如何将其扩展到三个结果中可能都为 null 的表。
感谢您的帮助。
【问题讨论】:
【参考方案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
【讨论】:
感谢您的代码。我会看看它。 ProductBounds 需要使用 PB.ProductName = PR.ProductName 但除此之外它看起来很棒!【参考方案2】:不要从 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
【讨论】:
我以前从未使用过联合体。我将不得不看看他们是如何工作的。感谢您的代码。【参考方案3】:您已经得到了其他应该可以使用的答案,但在我看来,这种类型的 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
【讨论】:
【参考方案4】:感谢您引导我朝着正确的方向前进。在我把它调整得恰到好处之前,我不得不摆弄这个问题一段时间,但现在效果很好。
我的最终代码和结果:
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
...
【讨论】:
以上是关于查找 T-SQL 以返回这些值的主要内容,如果未能解决你的问题,请参考以下文章