2009-02-25 7 views
1

J'essaye d'écrire une procédure stockée qui retournera deux valeurs calculées pour chaque enregistrement selon les règles ci-dessous, mais je n'ai pas compris comment structurer le SQL pour faire ça arrive. J'utilise SQL Server 2008.Trouver le T-SQL pour retourner ces valeurs

D'abord, les tables pertinentes et les champs qui importent au problème.

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 

Et ce que je suis en train de revenir. Je souhaite renvoyer une limite supérieure et une limite inférieure calculées pour chaque enregistrement TemplateMeasurements dont l'ID de modèle correspond à l'enregistrement ProductionRuns ayant l'ID d'exécution fourni.

Les limites supérieure et inférieure calculées obtiennent fondamentalement la limite la plus étroite qui peut être obtenue en raison des limites simples, de conteneur et de produit, si elles se qualifient.

Si un enregistrement SimpleBounds existe avec le MeasurementTypeID et le TemplateID corrects, alors cela devient l'une des limites qualifiantes pour un MeasurementTypeID particulier et un enregistrement de TemplateMeasurements.

Pour qu'un enregistrement ContainerBound puisse être qualifié, le paramètre TemplateID et MeasurementTypeID doivent correspondre, mais le nom du conteneur doit également correspondre à la valeur de ContainerName dans l'enregistrement ProductionRuns. Aussi pour ProductBounds, la même chose est vraie, mais pour ProductName.

Pour un MeasurementTypeID particulier, prenez toutes les limites qualifiantes et trouvez le moins de limite supérieure, et ce sera la limite supérieure calculée qui doit être retournée. Trouver la plus grande limite inférieure des qualificatifs et ce sera la limite inférieure retournée.

Je ne sais pas comment mettre en place SQL pour faire cela.

En outre, si aucune des trois tables liées ne se qualifie pour un MeasurementTypeID particulier, alors null peut être retourné. Ma pensée serait une sorte de jointure externe gauche, mais je ne suis pas sûr de savoir comment l'étendre à trois tables qui pourraient toutes avoir une valeur nulle dans les résultats.

Merci pour l'aide.

Répondre

1

Je n'ai pas le temps de tester ce moment, mais nous espérons que cela vous vous en approcher:

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

Merci pour le code. Je vais y jeter un coup d'oeil. ProductBounds doit utiliser PB.ProductName = PR.ProductName mais à part ça, il a l'air génial! –

+0

Ahh, couper et coller erreur ... Je vais le corriger maintenant –

1

ne pas enlever de la réponse de Tom H., mais vous pourriez aussi envisager d'approcher ce problème avec les syndicats au lieu de jointures pour aider à séparer les différentes règles supérieures/inférieures. Cela dépend de la façon dont vous pensez que les requêtes devront changer (le cas échéant) dans le futur.

La requête finit par être plus propre, en particulier sans toutes les règles CASE, mais elle peut ne pas être aussi utile dans les cas où les lignes TemplateMeasurement n'existent pas.

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 
+0

Je n'ai jamais utilisé les syndicats avant. Je vais devoir chercher comment ils fonctionnent. Merci pour le code. –

1

Vous avez d'autres réponses déjà que devraient travailler, mais à mon avis ce type de requête interne peut entraîner filles fusionnées la plus propre à la recherche, la plus maintenable à l'effondrement d'une hiérarchie horizontale en verticale, qui est fondamentalement votre problème:

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 
0

Merci de m'avoir conduit dans la bonne direction. J'ai dû bidouiller le problème pendant un moment avant de le régler correctement, mais ça fonctionne très bien maintenant.

Mon code final et les résultats:

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 

résultats partiels pour un cas particulier, 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 
... 
Questions connexes