Нахождение T-SQL для возврата этих значений - PullRequest
1 голос
/ 25 февраля 2009

Я пытаюсь написать хранимую процедуру, которая будет возвращать два вычисленных значения для каждой записи в соответствии с правилами ниже, но я не выяснил, как структурировать 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, у которой есть соответствующий TemplateID с записью ProductionRuns, у которой есть предоставленный runID.

Рассчитанные верхние и нижние границы в основном получают самую жесткую границу, которая может быть получена в результате простых, контейнерных и товарных границ, если они соответствуют требованиям.

Если существует запись SimpleBounds с правильными MeasurementTypeID и TemplateID, то она становится одной из квалификационных границ для конкретного MeasurementTypeID и записи TemplateMeasurements.

Чтобы запись ContainerBound соответствовала требованиям, TemplateID и MeasurementTypeID должны совпадать, но также ContainerName должно совпадать со значением для ContainerName в записи ProductionRuns. То же самое относится и к ProductBounds, но для ProductName.

Для конкретного MeasurementTypeID возьмите все подходящие границы и найдите наименьшую верхнюю границу, и это будет рассчитанная верхняя граница, которая должна быть возвращена. Найдите наибольшую нижнюю границу квалификаторов, и это будет возвращенная нижняя граница.

Однако я не знаю, как собрать SQL для этого.

Кроме того, если ни одна из трех связанных таблиц не подходит для определенного MeasurementTypeID, тогда может быть возвращено значение NULL.

Я бы подумал, что это будет какое-то левое внешнее объединение, но я не уверен, как расширить это до трех таблиц, которые могут иметь нулевые результаты.

Спасибо за помощь.

Ответы [ 4 ]

1 голос
/ 25 февраля 2009

Не отнимать от ответа Тома Х., но вы могли бы также рассмотреть решение этой проблемы с объединениями вместо объединений, чтобы помочь разделить различные верхние / нижние правила. Это зависит от того, как, по вашему мнению, нужно будет изменить запросы (если они вообще понадобятся) в будущем.

Запрос в конечном итоге выглядит чище, особенно без всех правил 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
1 голос
/ 25 февраля 2009

У вас уже есть другие ответы, которые должны работать, но, по моему мнению, этот тип внутреннего запроса 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
1 голос
/ 25 февраля 2009

У меня нет времени, чтобы проверить это прямо сейчас, но, надеюсь, это приблизит вас:

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
0 голосов
/ 26 февраля 2009

Спасибо, что привели меня в правильном направлении. Мне пришлось немного позаботиться о проблеме, прежде чем я все исправил, но теперь она прекрасно работает.

Мой окончательный код и результаты:

 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
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...