工作 Access SQL 查询的 T-SQL 迁移,在编写 IIF 的 CASE 替换时存在问题

发布于 2024-10-17 01:32:00 字数 2783 浏览 1 评论 0原文

我有两个表 BMReports_FPN_CurvesBMReports_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 包含将替换这些基值的值。

通常存在重复的 BOA 值,并且 Access SQL 语句中的嵌套 IIF 语句包含一条规则,用于选择任意时间点的 FPN、最大 BOA 值或最小 BOA 值之一。规则规定:

1)如果没有BOA值,则使用FPN值
2) 如果存在BOA值且小于FPN,则查找并使用Min BOA值
3)如果有一个BOA值并且它大于FPN,找到并使用最大BOA值

Access SQL查询工作完美,如下所示:

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

I have two tables BMReports_FPN_Curves and BMReports_BOA_Curves each consisting of a Name, Datetime, Period and Value, for example:

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

With the RunDate field incrementing by one minute (this c.1440 records per day) and the Periods being 1-48. In BMReports_FPN_Curves I have a complete data set for each time period and BMReports_BOA_Curves contains the values that will replace these base values.

There are usually duplicate BOA values and a nested IIF statement in the Access SQL statement contained a rule to pick one of either the FPN, the max BOA value or Min BOA value for any point in time. The rule stated:

1) If there is no BOA value, use the FPN value
2) If there is a BOA value and it is less than the FPN, find and use the Min BOA value
3) If there is a BOA value and it is greater than the FPN, find and use the Max BOA value

The Access SQL query works perfectly and is as follows:

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

I've re-written the bulk of the query in T-SQL (querying the same SQL Server data source) and have the LEFT JOIN, GROUP BY and HAVING elements all working but I am getting stuck on the CASE WHEN replacement for the IFF and would really appreciate a hand if some has a few moments spare.

The SQL Query as it currently stands:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

安穩 2024-10-24 01:32:00
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
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
鼻尖触碰 2024-10-24 01:32:00

您可能最好使用 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 的数据库,您还可以在 from (内联视图)中使用选择。顺便说一下,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

You're probably better off using a CTE to do all the aggregate calculations and then doing your case statement off that

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 

For DB's that don't support CTEs you can also use a select inside the from (inline view). Incidentally Access supports this.

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
沧笙踏歌 2024-10-24 01:32:00

您是否尝试过将 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

我无法访问您的完整架构或数据,因此我无法测试翻译,但我相信它在语法上是正确的。

Have you tried a more literal translation of the IIF to CASE? For example, your IIF chain looks something like this:

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

So a literal translation would be something like this:

(
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

I don't have access to your full schema nor data so I cannot test the translation, but I believe it is syntactically correct.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文