在DB2 SQL中,是否可以在SELECT语句中设置一个变量多次使用..?
In DB2 SQL, is it possible to set a variable in the SELECT statement to use multiple times..?
在 DB2 SQL 中,是否可以 SET
具有 SELECT
语句中 returned 字段内容的变量,以便多次使用在同一 SELECT
语句中进一步计算字段和条件?
目的是压缩和精简代码,在开始时计算一次,然后多次使用...包括HAVING
、WHERE
和ORDER BY
.
老实说,我不确定这在 SQL 的任何版本中是否可行,更不用说 DB2 了。
这是在带有 DB2 SQL v6 的 IBM iSeries 8202 上,不幸的是,目前不适合升级。这是一个非常古老且混乱的数据库,我无法控制它。我必须定期在我的 SQL.
中包含 "cleanup functions"
为了澄清问题,请注意以下伪代码。实际工作代码如下。
DECLARE smnum INTEGER --Not sure if this is correct.
SELECT
-- This is where I'm not sure what to do.
SET CAST((CASE WHEN %smnum%='' THEN '0' ELSE %smnum% END) AS INTEGER) INTO smnum,
%smnum% AS sm,
invdat,
invno,
daqty,
dapric,
dacost,
(dapric-dacost)*daqty AS profit
FROM
saleshistory
WHERE
%smNum% = 30
ORDER BY
%smnum%
下面是我的实际工作SQL。针对 2017 年或 2016 年进行调整后,它可以 return >10K 行,具体取决于销售人员。完整的 table 有 >22M 行。
CASE((CAST...
函数的那个 buttload 是我想用变量替换的。这不是唯一的例子。如果我能让它工作,我还有许多其他查询可以从该技术中受益。
SELECT
CAST((CASE WHEN TRIM(DASM#)='' THEN '0' ELSE TRIM(DASM#) END) AS INTEGER) AS DASM,
DAIDAT,
DAINV# AS DAINV,
DALIN# AS DALIN,
CAST(TRIM(DAITEM) AS INTEGER) AS DAITEM,
TRIM(DABSW) AS DABSW,
TRIM(DAPCLS) AS DAPCLS,
DAQTY,
DAPRIC,
DAICOS,
DADPAL,
(DAPRIC-DAICOS+DADPAL)*DAQTY AS PROFIT
FROM
VIPDTAB.DAILYV
WHERE
CAST((CASE WHEN TRIM(DASM#)='' THEN '0' ELSE TRIM(DASM#) END) AS INTEGER)=30 AND
TRIM(DABSW)='B' AND
DAIDAT BETWEEN (YEAR(CURDATE())*10000) AND (((YEAR(CURDATE())+1)*10000)-1) AND
CAST(TRIM(DACOMP) AS INTEGER)=1
ORDER BY
CAST((CASE WHEN TRIM(DASM#)='' THEN '0' ELSE TRIM(DASM#) END) AS INTEGER),
DAIDAT,
DAINV#,
DALIN#
只需使用子查询或 CTE。我无法弄清楚你想要的实际逻辑,但结构如下所示:
select . . .
from (select d.*,
(CASE . . . END) as calc_field
from VIPDTAB.DAILYV d
) d
不需要变量声明。
这是 Gordon 建议的 sub-query 你的 SQL 的样子:
SELECT
DASM,
DAIDAT,
DAINV# AS DAINV,
DALIN# AS DALIN,
CAST(DAITEM AS INTEGER) AS DAITEM,
TRIM(DABSW) AS DABSW,
TRIM(DAPCLS) AS DAPCLS,
DAQTY,
DAPRIC,
DAICOS,
DADPAL,
(DAPRIC-DAICOS+DADPAL)*DAQTY AS PROFIT
FROM
(SELECT
D.*,
CAST((CASE WHEN D.DASM#='' THEN '0' ELSE D.DASM# END) AS INTEGER) AS DASM
FROM VIPDTAB.DAILYV D
) D
WHERE
DASM=30 AND
TRIM(DABSW)='B' AND
DAIDAT BETWEEN (YEAR(CURDATE())*10000) AND (((YEAR(CURDATE())+1)*10000)-1) AND
CAST(DACOMP AS INTEGER)=1
ORDER BY
DASM,
DAIDAT,
DAINV#,
DALIN#
请注意,我删除了很多 trim()
函数,您可能会删除其余的。 IBM 解决 Varchar 与 Char 比较问题的方法是忽略尾随空白。所以 trim(anything) = ''
与 anything = ''
相同。由于 cast(' 123 ' as integer)
= 123
,我也从转换函数中删除了 trims。此外 trim(dabsw) = 'B'
与 dabsw = 'B'
相同,只要 'B'
是 dabsw
中的第一个字符。因此,如果您只关心尾随空白,您甚至可以删除 trim。
这里是一些基于评论的附加说明。上面这段不是在说auto-trim。固定长度字段将始终 return 作为固定长度字段,尾随空白将保留。但在比较和表达式中,尾随空格不重要,甚至是障碍,它们将被忽略。在尾随空格很重要的表达式中,如连接,尾随空格不会被忽略。另一件事,trim()
删除前导和尾随空白。如果您使用 trim()
将固定长度的字符字段读入 Varchar
,那么 rtrim()
可能是更好的选择,因为它只删除尾随空格。
此外,我没有检查您的字段以确保我得到了您需要的一切,我只是在 sub-query 中使用了 *
。为了提高性能,最好只 return 您需要的字段。因此,如果将 D.*
替换为实际字段列表,则可以删除 sub-query 的 from 子句中的相关名称。但是,sub-query 本身仍然需要关联子句。
我的验证是使用 IBM i v7.1 完成的。
您可以将 case 语句封装在一个视图中。我什至有花哨的利润计算器供您按利润排序。现在您遇到的最大问题是计算列视图上的 CCSID,但这是另一个问题。
create or replace view VIPDTAB.DAILYVQ as
SELECT
CAST((CASE WHEN TRIM(DASM#)='' THEN '0' ELSE TRIM(DASM#) END) AS INTEGER) AS DASM,
DAIDAT,
DAINV# AS DAINV,
DALIN# AS DALIN,
CAST(TRIM(DAITEM) AS INTEGER) AS DAITEM,
TRIM(DABSW) AS DABSW,
TRIM(DAPCLS) AS DAPCLS,
DAQTY,
DAPRIC,
DAICOS,
DADPAL,
(DAPRIC-DAICOS+DADPAL)*DAQTY AS PROFIT
FROM
VIPDTAB.DAILYV
现在你可以
select dasm, count(*) from vipdtab.dailyvq where dasm = 0 group by dasm order by dasm
或
select * from vipdtab.dailyvq order by profit desc
在 DB2 SQL 中,是否可以 SET
具有 SELECT
语句中 returned 字段内容的变量,以便多次使用在同一 SELECT
语句中进一步计算字段和条件?
目的是压缩和精简代码,在开始时计算一次,然后多次使用...包括HAVING
、WHERE
和ORDER BY
.
老实说,我不确定这在 SQL 的任何版本中是否可行,更不用说 DB2 了。
这是在带有 DB2 SQL v6 的 IBM iSeries 8202 上,不幸的是,目前不适合升级。这是一个非常古老且混乱的数据库,我无法控制它。我必须定期在我的 SQL.
中包含 "cleanup functions"为了澄清问题,请注意以下伪代码。实际工作代码如下。
DECLARE smnum INTEGER --Not sure if this is correct.
SELECT
-- This is where I'm not sure what to do.
SET CAST((CASE WHEN %smnum%='' THEN '0' ELSE %smnum% END) AS INTEGER) INTO smnum,
%smnum% AS sm,
invdat,
invno,
daqty,
dapric,
dacost,
(dapric-dacost)*daqty AS profit
FROM
saleshistory
WHERE
%smNum% = 30
ORDER BY
%smnum%
下面是我的实际工作SQL。针对 2017 年或 2016 年进行调整后,它可以 return >10K 行,具体取决于销售人员。完整的 table 有 >22M 行。
CASE((CAST...
函数的那个 buttload 是我想用变量替换的。这不是唯一的例子。如果我能让它工作,我还有许多其他查询可以从该技术中受益。
SELECT
CAST((CASE WHEN TRIM(DASM#)='' THEN '0' ELSE TRIM(DASM#) END) AS INTEGER) AS DASM,
DAIDAT,
DAINV# AS DAINV,
DALIN# AS DALIN,
CAST(TRIM(DAITEM) AS INTEGER) AS DAITEM,
TRIM(DABSW) AS DABSW,
TRIM(DAPCLS) AS DAPCLS,
DAQTY,
DAPRIC,
DAICOS,
DADPAL,
(DAPRIC-DAICOS+DADPAL)*DAQTY AS PROFIT
FROM
VIPDTAB.DAILYV
WHERE
CAST((CASE WHEN TRIM(DASM#)='' THEN '0' ELSE TRIM(DASM#) END) AS INTEGER)=30 AND
TRIM(DABSW)='B' AND
DAIDAT BETWEEN (YEAR(CURDATE())*10000) AND (((YEAR(CURDATE())+1)*10000)-1) AND
CAST(TRIM(DACOMP) AS INTEGER)=1
ORDER BY
CAST((CASE WHEN TRIM(DASM#)='' THEN '0' ELSE TRIM(DASM#) END) AS INTEGER),
DAIDAT,
DAINV#,
DALIN#
只需使用子查询或 CTE。我无法弄清楚你想要的实际逻辑,但结构如下所示:
select . . .
from (select d.*,
(CASE . . . END) as calc_field
from VIPDTAB.DAILYV d
) d
不需要变量声明。
这是 Gordon 建议的 sub-query 你的 SQL 的样子:
SELECT
DASM,
DAIDAT,
DAINV# AS DAINV,
DALIN# AS DALIN,
CAST(DAITEM AS INTEGER) AS DAITEM,
TRIM(DABSW) AS DABSW,
TRIM(DAPCLS) AS DAPCLS,
DAQTY,
DAPRIC,
DAICOS,
DADPAL,
(DAPRIC-DAICOS+DADPAL)*DAQTY AS PROFIT
FROM
(SELECT
D.*,
CAST((CASE WHEN D.DASM#='' THEN '0' ELSE D.DASM# END) AS INTEGER) AS DASM
FROM VIPDTAB.DAILYV D
) D
WHERE
DASM=30 AND
TRIM(DABSW)='B' AND
DAIDAT BETWEEN (YEAR(CURDATE())*10000) AND (((YEAR(CURDATE())+1)*10000)-1) AND
CAST(DACOMP AS INTEGER)=1
ORDER BY
DASM,
DAIDAT,
DAINV#,
DALIN#
请注意,我删除了很多 trim()
函数,您可能会删除其余的。 IBM 解决 Varchar 与 Char 比较问题的方法是忽略尾随空白。所以 trim(anything) = ''
与 anything = ''
相同。由于 cast(' 123 ' as integer)
= 123
,我也从转换函数中删除了 trims。此外 trim(dabsw) = 'B'
与 dabsw = 'B'
相同,只要 'B'
是 dabsw
中的第一个字符。因此,如果您只关心尾随空白,您甚至可以删除 trim。
这里是一些基于评论的附加说明。上面这段不是在说auto-trim。固定长度字段将始终 return 作为固定长度字段,尾随空白将保留。但在比较和表达式中,尾随空格不重要,甚至是障碍,它们将被忽略。在尾随空格很重要的表达式中,如连接,尾随空格不会被忽略。另一件事,trim()
删除前导和尾随空白。如果您使用 trim()
将固定长度的字符字段读入 Varchar
,那么 rtrim()
可能是更好的选择,因为它只删除尾随空格。
此外,我没有检查您的字段以确保我得到了您需要的一切,我只是在 sub-query 中使用了 *
。为了提高性能,最好只 return 您需要的字段。因此,如果将 D.*
替换为实际字段列表,则可以删除 sub-query 的 from 子句中的相关名称。但是,sub-query 本身仍然需要关联子句。
我的验证是使用 IBM i v7.1 完成的。
您可以将 case 语句封装在一个视图中。我什至有花哨的利润计算器供您按利润排序。现在您遇到的最大问题是计算列视图上的 CCSID,但这是另一个问题。
create or replace view VIPDTAB.DAILYVQ as
SELECT
CAST((CASE WHEN TRIM(DASM#)='' THEN '0' ELSE TRIM(DASM#) END) AS INTEGER) AS DASM,
DAIDAT,
DAINV# AS DAINV,
DALIN# AS DALIN,
CAST(TRIM(DAITEM) AS INTEGER) AS DAITEM,
TRIM(DABSW) AS DABSW,
TRIM(DAPCLS) AS DAPCLS,
DAQTY,
DAPRIC,
DAICOS,
DADPAL,
(DAPRIC-DAICOS+DADPAL)*DAQTY AS PROFIT
FROM
VIPDTAB.DAILYV
现在你可以
select dasm, count(*) from vipdtab.dailyvq where dasm = 0 group by dasm order by dasm
或
select * from vipdtab.dailyvq order by profit desc