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