查找T-SQL以返回这些值

时间:2009-02-25 15:55:09

标签: sql sql-server tsql join

我正在尝试编写一个存储过程,它将根据下面的规则为每条记录返回两个计算值,但我还没弄清楚如何构建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。

我的想法是某种左外连接,但我不知道如何将其扩展到三个表中,这些表在结果中都可能为空。

感谢您的帮助。

4 个答案:

答案 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
...