Migration T-SQL de la requête SQL d'accès au travail avec un problème sur la rédaction du remplacement du cas pour IIF

StackOverflow https://stackoverflow.com/questions/4972952

Question

j'ai deux tables BMREPORTS_FPN_CURVES et BMREPORTS_BOA_CURVES Chacun composé d'un nom, d'une datetime, d'une période et d'une valeur, par exemple:

BM_UNIT_NAME   RunDate               Period  FPN (or BOA)
T_DRAXX-1      2010-12-01 00:03:00   1       497

Avec le champ Rundate incrémentant d'une minute (ce c.1440 enregistre par jour) et les périodes étant de 1 à 48. Dans BMREPORTS_FPN_CURVES J'ai un ensemble de données complet pour chaque période et BMREPORTS_BOA_CURVES Contient les valeurs qui remplaceront ces valeurs de base.

Il y a généralement des valeurs BOA en double et une instruction IIF imbriquée dans le Accéder L'instruction SQL contenait une règle pour choisir l'une des FPN, la valeur BOA max ou la valeur MIN BOA pour tout point dans le temps. La règle indiquait:

1) S'il n'y a pas de valeur BOA, utilisez la valeur FPN
2) S'il y a une valeur BOA et qu'elle est inférieure au FPN, trouvez et utilisez la valeur Min BOA
3) S'il y a une valeur BOA et qu'elle est supérieure au FPN, trouvez et utilisez la valeur BOA maximale

La Accéder à la requête SQL Fonctionne parfaitement et est le suivant:

SELECT 
dbo_BMReports_FPN_Curves.BM_Unit_Name, 
dbo_BMReports_FPN_Curves.RunDate, 
dbo_BMReports_FPN_Curves.Period, 
dbo_BMReports_FPN_Curves.PN_Level, 

IIf(IIf(Min([dbo_BMReports_BOA_Curves]![PN_Level]) <[dbo_BMReports_FPN_Curves]![PN_Level],Min([dbo_BMReports_BOA_Curves]! [PN_Level]),Max([dbo_BMReports_BOA_Curves]![PN_Level])) Is Null, [dbo_BMReports_FPN_Curves]![PN_Level],
IIf(Min([dbo_BMReports_BOA_Curves]![PN_Level])<[dbo_BMReports_FPN_Curves]! [PN_Level],Min([dbo_BMReports_BOA_Curves]! [PN_Level]),Max([dbo_BMReports_BOA_Curves]![PN_Level]))) AS BOA

FROM dbo_BMReports_FPN_Curves LEFT JOIN dbo_BMReports_BOA_Curves ON  (dbo_BMReports_FPN_Curves.RunDate = dbo_BMReports_BOA_Curves.RunDate) AND  (dbo_BMReports_FPN_Curves.BM_Unit_Name = dbo_BMReports_BOA_Curves.BM_Unit_Name)

GROUP BY dbo_BMReports_FPN_Curves.BM_Unit_Name, dbo_BMReports_FPN_Curves.RunDate, dbo_BMReports_FPN_Curves.Period, dbo_BMReports_FPN_Curves.PN_Level

HAVING (((dbo_BMReports_FPN_Curves.BM_Unit_Name)='T_DRAXX-1'));

J'ai réécrit la majeure partie de la requête en T-SQL (interroger la même source de données SQL Server) et j'ai la jointure de gauche, groupe par et ayant des éléments qui fonctionnent tous, mais je suis coincé sur le boîtier lors du remplacement de l'IFF Et apprécierait vraiment une main si certains ont quelques instants de rechange.

La requête SQL telle qu'elle est actuellement:

SELECT 
BMReports_FPN_Curves.BM_Unit_Name, 
BMReports_FPN_Curves.RunDate, 
BMReports_FPN_Curves.Period,
AVG(BMReports_FPN_Curves.PN_Level) AS FPN,

    CASE
      WHEN BMReports_BOA_Curves.PN_Level IS NULL THEN AVG(BMReports_FPN_Curves.PN_Level)
      WHEN MIN(BMReports_BOA_Curves.PN_Level) IS <  AVG(BMReports_FPN_Curves.PN_Level) THEN MIN(BMReports_BOA_Curves.PN_Level)
      ELSE MAX(BMReports_BOA_Curves.PN_Level)
    END AS BOA

FROM BMReports_FPN_Curves 
  LEFT JOIN BMReports_BOA_Curves ON BMReports_FPN_Curves.BM_Unit_Name = BMReports_BOA_Curves.BM_Unit_Name
  AND  BMReports_FPN_Curves.RunDate = BMReports_BOA_Curves.RunDate

GROUP BY BMReports_FPN_Curves.BM_Unit_Name, BMReports_FPN_Curves.RunDate, BMReports_FPN_Curves.Period
HAVING BMReports_FPN_Curves.BM_Unit_Name = 'T_DRAXX-1'
ORDER BY BMReports_FPN_Curves.BM_Unit_Name, BMReports_FPN_Curves.RunDate, BMReports_FPN_Curves.Period
Était-ce utile?

La solution

SELECT  fc.BM_Unit_Name
        , fc.RunDate
        , fc.Period
        , CASE 
          WHEN AVG(bc.PN_Level) IS NULL THEN AVG(fc.PN_Level)             -- No BOA Value, use the FPN Value
          WHEN MIN(bc.PN_Level) < AVG(fc.PN_Level) THEN MIN(bc.PN_Level) -- BOA Value is less than the FPN, use the BOA Value
          ELSE MAX(bc.PN_Level)                                          -- BOA Value is greater than the FPN, use the BOA Value
          END 
FROM    dbo.BMReports_FPN_Curves fc
        LEFT JOIN dbo.BMReports_BOA_Curves bc ON fc.RunDate = bc.RunDate        
                                                 AND fc.BM_Unit_Name = bc.BM_Unit_Name
WHERE   fc.BM_Unit_Name ='T_DRAXX-1'
GROUP BY
        fc.BM_Unit_Name
        , fc.RunDate
        , fc.Period

Autres conseils

Vous feriez probablement mieux d'utiliser un CTE pour faire tous les calculs agrégés, puis faire votre déclaration de cas

WITH cte 
     AS (SELECT bmreports_fpn_curves.bm_unit_name, 
                bmreports_fpn_curves.rundate, 
                bmreports_fpn_curves.period, 
                AVG(bmreports_fpn_curves.pn_level) AS fpn, 
                AVG(bmreports_fpn_curves.pn_level) AS boa, 
                MIN(bmreports_boa_curves.pn_level) minboa, 
                MAX(bmreports_fpn_curves.pn_level) maxfpn 
         FROM   bmreports_fpn_curves 
                LEFT JOIN bmreports_boa_curves 
                  ON bmreports_fpn_curves.bm_unit_name = 
                     bmreports_boa_curves.bm_unit_name 
                     AND bmreports_fpn_curves.rundate = 
                         bmreports_boa_curves.rundate 
         GROUP  BY bmreports_fpn_curves.bm_unit_name, 
                   bmreports_fpn_curves.rundate, 
                   bmreports_fpn_curves.period 
         HAVING bmreports_fpn_curves.bm_unit_name = 'T_DRAXX-1') 
SELECT bm_unit_name, 
       rundate, 
       period ,
       CASE 
              WHEN BOA IS NULL THEN FPN 
              WHEN BOA < FPN THEN MinBoa
              WEHN BOA > FPN THEN MaxBoa
              ELSE -- BOA = FPN THEN WHAT?
       END as BOA
FROM   cte 

Pour les DB qui ne prennent pas en charge les CTES, vous pouvez également utiliser un Select à l'intérieur de la (vue en ligne). Soit dit en passant, l'accès prend en charge cela.

SELECT bm_unit_name, 
       rundate, 
       period ,
       CASE 
              WHEN BOA IS NULL THEN FPN 
              WHEN BOA < FPN THEN MinBoa
              WEHN BOA > FPN THEN MaxBoa
              ELSE -- BOA = FPN THEN WHAT?
       END as BOA
  FROM (
       SELECT bmreports_fpn_curves.bm_unit_name, 
                bmreports_fpn_curves.rundate, 
                bmreports_fpn_curves.period, 
                AVG(bmreports_fpn_curves.pn_level) AS fpn, 
                AVG(bmreports_fpn_curves.pn_level) AS boa, 
                MIN(bmreports_boa_curves.pn_level) minboa, 
                MAX(bmreports_fpn_curves.pn_level) maxfpn 
         FROM   bmreports_fpn_curves 
                LEFT JOIN bmreports_boa_curves 
                  ON bmreports_fpn_curves.bm_unit_name = 
                     bmreports_boa_curves.bm_unit_name 
                     AND bmreports_fpn_curves.rundate = 
                         bmreports_boa_curves.rundate 
         GROUP  BY bmreports_fpn_curves.bm_unit_name, 
                   bmreports_fpn_curves.rundate, 
                   bmreports_fpn_curves.period 
         HAVING bmreports_fpn_curves.bm_unit_name = 'T_DRAXX-1')   ) t

Avez-vous essayé une traduction plus littérale de l'IIF à cas? Par exemple, votre chaîne IIF ressemble à ceci:

IIf
(
    IIf
    (
        Min([dbo_BMReports_BOA_Curves]![PN_Level]) < [dbo_BMReports_FPN_Curves]![PN_Level], 
        Min([dbo_BMReports_BOA_Curves]![PN_Level]),
        Max([dbo_BMReports_BOA_Curves]![PN_Level])
    ) Is Null,
    [dbo_BMReports_FPN_Curves]![PN_Level],
    IIf
    (
        Min([dbo_BMReports_BOA_Curves]![PN_Level]) < [dbo_BMReports_FPN_Curves]![PN_Level],
        Min([dbo_BMReports_BOA_Curves]![PN_Level]),
        Max([dbo_BMReports_BOA_Curves]![PN_Level])
    )
) AS BOA

Une traduction littérale serait donc quelque chose comme ceci:

(
case
    when 
        (
        case
            when Min(BMReports_BOA_Curves.PN_Level) < BMReports_FPN_Curves.PN_Level then
                Min(BMReports_BOA_Curves.PN_Level)
            else
                Max(BMReports_BOA_Curves.PN_Level)
        end
        ) is null then
        BMReports_FPN_Curves.PN_Level
    else
        (
            case
                when Min(BMReports_BOA_Curves.PN_Level) < BMReports_FPN_Curves.PN_Level then
                    Min(BMReports_BOA_Curves.PN_Level)
                else
                    Max(BMReports_BOA_Curves.PN_Level)
            end
        )
end
) as BOA

Je n'ai pas accès à votre schéma complet ni aux données, donc je ne peux pas tester la traduction, mais je pense qu'elle est syntaxiquement correcte.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top