Миграция T-SQL на работающий Access SQL Query с проблемой написания замены CASE для IIF - PullRequest
2 голосов
/ 11 февраля 2011

У меня есть две таблицы BMReports_FPN_Curves и BMReports_BOA_Curves , каждая из которых состоит из имени, даты, времени, периода и значения, например:

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

С полем RunDate, увеличивающимся на одну минуту (это c.1440 записей в день), и периоды составляют 1-48. В BMReports_FPN_Curves у меня есть полный набор данных для каждого периода времени, а BMReports_BOA_Curves содержит значения, которые заменят эти базовые значения.

Обычно в SQL-операторе Access есть дублированные значения BOA и вложенный оператор IIF, содержащий правило для выбора одного из FPN, максимального значения BOA или минимального значения BOA для любого момента времени. Правило гласило:

1) Если значение BOA отсутствует, используйте значение FPN
2) Если есть значение BOA и оно меньше, чем FPN, найдите и используйте значение Min BOA
3) Если есть значение BOA, и оно больше, чем FPN, найдите и используйте значение Max BOA

SQL-запрос Access отлично работает и работает следующим образом:

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'));

Я переписал большую часть запроса в T-SQL (запрос к одному и тому же источнику данных SQL Server) и все элементы LEFT JOIN, GROUP BY и HAVING работают, но я застрял на замене CASE WHEN для IFF и был бы очень признателен за руку, если бы у некоторых было несколько свободных моментов.

SQL-запрос в его нынешнем виде:

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

Ответы [ 3 ]

2 голосов
/ 11 февраля 2011
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
1 голос
/ 11 февраля 2011

Вам, вероятно, лучше использовать CTE для выполнения всех агрегатных вычислений, а затем делать из этого утверждения case

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 

Для баз данных, которые не поддерживают CTE, вы также можете использовать выбор внутриот (встроенный вид).Кстати, Access поддерживает это.

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

Вы пробовали более буквальный перевод IIF в CASE? Например, ваша цепочка IIF выглядит примерно так:

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

Таким образом, буквальный перевод будет выглядеть примерно так:

(
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

У меня нет доступа к вашей полной схеме или данным, поэтому я не могу проверить перевод, но я считаю, что он синтаксически правильный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...