使用 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 年前发布)。
数据库引擎是一款名为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 年前发布)。