使用 SQL 处理由零除引起的错误

Handle error due to division by zero using SQL

数据库引擎是一款名为Paprika 的财务软件。其目的是为特定部门提取 2018 年 12 月的收入。

(2018 年 12 月 3 个数据库(英国、美国、巴西)的项目价值工作 prob/FX 比率)(部门工作时间基于 grade/total 小时数据库)

零值来自最后一部分(最后 3 个分界线)- 在为每个项目按等级提取小时数时,其中许多小时数为零。

以下是服务台的评论:
"The person who coded the view could have added IF statements to the calculation's to let Paprika know what to do when it encounters a divide by zero, this would have stopped the view falling over."

出现错误的代码:

(((COALESCE((SELECT SUM(JF_AMOUNT) 
             FROM MAV.UK.JOB_BUD_FORECAST, MAV.UK.NOMINAL_PERIOD 
             WHERE JF_JO_MN=JO_MN AND JF_FORECAST_TYPE=1 AND JF_NP_MN=NP_MN AND NP_PERIOD_KEY = '201812'),
            (SELECT SUM(JF_AMOUNT) 
             FROM MAV.USA.JOB_BUD_FORECAST, MAV.USA.NOMINAL_PERIOD
             WHERE JF_JO_MN=(JO_MN) AND JF_FORECAST_TYPE=1 AND JF_NP_MN=NP_MN AND NP_PERIOD_KEY = '201812'),
            (SELECT SUM(JF_AMOUNT)
             FROM MAV.BR.JOB_BUD_FORECAST, MAV.BR.NOMINAL_PERIOD 
             WHERE JF_JO_MN=(JO_MN) AND JF_FORECAST_TYPE=1 AND JF_NP_MN=NP_MN AND NP_PERIOD_KEY = '201812'),
            0))*JO_PROBABILITY/100)/CUR_RATE)*
    COALESCE(((SELECT SUM(JB_CHARGE) 
               FROM MAV.UK.JOB_BUDFORM 
               WHERE JB_JO_MN=JO_MN AND JB_GRADE IN('AUT', 'EDT', 'FMAN', 'FPRN', 'FDIR', 'SAUT', 'FDIR') AND JB_REV=JO_BUD_REVISION)/
              (SELECT SUM(JB_CHARGE) 
               FROM MAV.UK.JOB_BUDFORM 
               WHERE JB_JO_MN=JO_MN AND JB_GRADE NOT IN(' ') AND JB_REV=JO_BUD_REVISION)),
             ((SELECT SUM(JB_CHARGE) 
               FROM MAV.USA.JOB_BUDFORM 
               WHERE JB_JO_MN=(JO_MN) AND JB_GRADE IN('AUT', 'EDT', 'FMAN', 'FPRN', 'FDIR', 'SAUT', 'FDIR') AND JB_REV=JO_BUD_REVISION)/
              (SELECT SUM(JB_CHARGE) 
               FROM MAV.USA.JOB_BUDFORM
               WHERE JB_JO_MN=(JO_MN) AND JB_GRADE NOT IN(' ') AND JB_REV=JO_BUD_REVISION)),
             ((SELECT SUM(JB_CHARGE) 
               FROM MAV.BR.JOB_BUDFORM 
               WHERE JB_JO_MN=(JO_MN) AND JB_GRADE IN('AUT', 'EDT', 'FMAN', 'FPRN', 'FDIR', 'SAUT', 'FDIR') AND JB_REV=JO_BUD_REVISION)/
              (SELECT SUM(JB_CHARGE) FROM MAV.BR.JOB_BUDFORM WHERE JB_JO_MN=(JO_MN) AND JB_GRADE NOT IN(' ') AND JB_REV=JO_BUD_REVISION)),
             0)

我的天:在SQL中没有select那样的select,我们必须使用子查询and/or join。

不好SQL

(select A from toto where A=T.AA), T.*
from mytable T

正确 SQL (ANSI 92)

select toto.A, T.*
from toto 
inner join T
on toto.A =T.AA

正确 SQL(旧 SQL 或由机器人生成)

select toto.A, T.*
from toto,T
where toto.A =T.AA

如果 B 可以无误地等于零,则回答 A / B 的问题:

select
case 
  when coalesce(T.B,0)<> 0 
    then T.A/T.B 
end
from my_table as T

select
case 
  when coalesce(T.B,0)<> 0 
    then T.A/T.B 
  else 0
end
from my_table as T

对该查询要做的第一件事是对其进行格式化,以便仅供人类阅读,例如我把那个怪物带到 an online T-SQL formatting tool 添加了单词 select 然后粘贴然后点击格式按钮显示这个:

SELECT
    (((COALESCE( (
        SELECT
            SUM( JF_AMOUNT )
        FROM MAV.UK.JOB_BUD_FORECAST
           , MAV.UK.NOMINAL_PERIOD
        WHERE JF_JO_MN = JO_MN
        AND JF_FORECAST_TYPE = 1
        AND JF_NP_MN = NP_MN
        AND NP_PERIOD_KEY = '201812'
    )
    , (
        SELECT
            SUM( JF_AMOUNT )
        FROM MAV.USA.JOB_BUD_FORECAST
           , MAV.USA.NOMINAL_PERIOD
        WHERE JF_JO_MN = (JO_MN)
        AND JF_FORECAST_TYPE = 1
        AND JF_NP_MN = NP_MN
        AND NP_PERIOD_KEY = '201812'
    )
    , (
        SELECT
            SUM( JF_AMOUNT )
        FROM MAV.BR.JOB_BUD_FORECAST
           , MAV.BR.NOMINAL_PERIOD
        WHERE JF_JO_MN = (JO_MN)
        AND JF_FORECAST_TYPE = 1
        AND JF_NP_MN = NP_MN
        AND NP_PERIOD_KEY = '201812'
    )
    , 0 ))
    * JO_PROBABILITY / 100)
    / CUR_RATE
    ) * COALESCE( ((
        SELECT
            SUM( JB_CHARGE )
        FROM MAV.UK.JOB_BUDFORM
        WHERE JB_JO_MN = JO_MN
        AND JB_GRADE IN ('AUT', 'EDT', 'FMAN', 'FPRN', 'FDIR', 'SAUT', 'FDIR')
        AND JB_REV = JO_BUD_REVISION
    )
    / (
        SELECT
            SUM( JB_CHARGE )
        FROM MAV.UK.JOB_BUDFORM
        WHERE JB_JO_MN = JO_MN
        AND JB_GRADE NOT IN (' ')
        AND JB_REV = JO_BUD_REVISION
    )
    ), ((
        SELECT
            SUM( JB_CHARGE )
        FROM MAV.USA.JOB_BUDFORM
        WHERE JB_JO_MN = (JO_MN)
        AND JB_GRADE IN ('AUT', 'EDT', 'FMAN', 'FPRN', 'FDIR', 'SAUT', 'FDIR')
        AND JB_REV = JO_BUD_REVISION
    )
    / (
        SELECT
            SUM( JB_CHARGE )
        FROM MAV.USA.JOB_BUDFORM
        WHERE JB_JO_MN = (JO_MN)
        AND JB_GRADE NOT IN (' ')
        AND JB_REV = JO_BUD_REVISION
    )
    ), ((
        SELECT
            SUM( JB_CHARGE )
        FROM MAV.BR.JOB_BUDFORM
        WHERE JB_JO_MN = (JO_MN)
        AND JB_GRADE IN ('AUT', 'EDT', 'FMAN', 'FPRN', 'FDIR', 'SAUT', 'FDIR')
        AND JB_REV = JO_BUD_REVISION
    )
    / (
        SELECT
            SUM( JB_CHARGE )
        FROM MAV.BR.JOB_BUDFORM
        WHERE JB_JO_MN = (JO_MN)
        AND JB_GRADE NOT IN (' ')
        AND JB_REV = JO_BUD_REVISION
    )
    ), 0 )

我认为大部分数据可以作为 2 个连接子查询的来源,如下所示:

SELECT
  , jo.JO_MN           , jo.JO_BUD_REVISION
  , jo.JO_PROBABILITY  , jo.CUR_RATE
  , s1.SUM_JF_AMOUNT   , s2.SUM_JB_CHARGE_IN , s2.SUM_JB_CHARGE_NOT_IN
FROM unknown_table jo
LEFT JOIN (
        SELECT
            JF_JO_MN
          , SUM( JF_AMOUNT )                      AS SUM_JF_AMOUNT
        FROM MAV.UK.JOB_BUD_FORECAST
        INNER JOIN MAV.UK.NOMINAL_PERIOD ON JF_NP_MN = NP_MN
        WHERE JF_FORECAST_TYPE = 1
        AND NP_PERIOD_KEY = '201812'
        GROUP BY
            JF_JO_MN
    ) s1 ON JF_JO_MN = JO_MN
LEFT JOIN (
        SELECT
            JB_REV
          , SUM( CASE
                WHEN JB_GRADE IN ('AUT', 'EDT', 'FMAN', 'FPRN', 'FDIR', 'SAUT', 'FDIR') 
                THEN JB_CHARGE
            END )                                 AS SUM_JB_CHARGE_IN
          , SUM( CASE
                WHEN JB_GRADE NOT IN (' ') 
                THEN JB_CHARGE
            END )                                 AS SUM_JB_CHARGE_NOT_IN
        FROM MAV.UK.JOB_BUDFORM
        WHERE (
                JB_GRADE IN ('AUT', 'EDT', 'FMAN', 'FPRN', 'FDIR', 'SAUT', 'FDIR')
             OR JB_GRADE NOT IN (' ')
              )
        GROUP BY
            JB_REV
    ) s2 ON JB_REV = JO_BUD_REVISION

如果您使用这样的查询结构,您可以更轻松地访问想要的数字,并且 NULL 的问题也可以轻松解决。

注意您需要改进每个子查询的连接语法。帮自己一个忙,停止在 table 名称之间使用逗号,这将帮助您采用 "newer" 语法(25 年前发布)。