【问题标题】:Finding the T-SQL to return these values查找 T-SQL 以返回这些值
【发布时间】: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 的表。

感谢您的帮助。

【问题讨论】:

    标签: sql sql-server tsql join


    【解决方案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
      ...
      

      【讨论】:

        猜你喜欢
        • 2018-03-18
        • 2014-09-10
        • 1970-01-01
        • 2015-08-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-02
        • 2010-12-26
        相关资源
        最近更新 更多