【发布时间】:2019-09-18 22:33:31
【问题描述】:
编辑:我在原始问题的末尾添加了更多内容。
[原问题]:
在 DB2 SQL 表函数中,声明的全局临时表的范围是否可以限制为函数的当前实例......?这是 DB2-for-i v7r3m0。
我正在计划一个用于分析字符数据的表函数。为此,该函数需要一个临时表来缓存信息,然后这些信息将以不同的方式重复循环,直到获得结果。我的第一个想法是使用声明的全局临时表,但是有“全局”这个词。
为了提高效率,我想用ALLOW PARALLEL 和NOT FENCED 编写函数,但这两个选项似乎与DGTT 的性质相冲突。
另外,因为写入 DGTT 需要MODIFIES SQL DATA,所以我不确定是否有任何方法可以使用ALLOW PARALLEL,即使对函数进行了仔细设计。
documentation 让我有点困惑;也许我不明白什么?在开头的段落中说:
每个应用程序进程定义一个声明的临时表 同名的临时表有自己独特的描述。
然后在table-name 下显示:
如果声明的临时表,或者依赖的索引或视图 在已声明的临时表上已经存在同名的,一个 返回错误。
所以我想问一下:是否可以创建 DGTT 或任何其他类型的临时表,使其范围仅限于函数的当前实例..?
我可以随意为 DGTT 命名,但这会使代码复杂一些。理想情况下,我只想使用一个名称。
我的另一个想法是在 DGTT 中有一组由函数的输入参数填充的键列。然后该函数的所有实例可以共享一个 DGTT,但只能访问它们自己的行。
有人有什么建议吗..?
编辑:
好的,我已经连续工作了两天,终于创建了一个工作示例。 DGTT明显过剩;这些最初是 CTE,但我将它们全部转换为开发,以便在流程的每个步骤之后允许一个结果窗口。
最初的目的是成为一个带有一个输入参数和一个输出的标量函数,我认为它可以非常令人满意地成为一个没有输入参数的表函数。
我最终得到的结果非常有效,而且比我的前几次尝试快得多。事实上,我可以很容易地保持原样,但我会将 DGTT 转换回 CTE,看看效率是否有任何变化。可能我看不到任何变化,在这种情况下,没有 DGTT 会使我的整个 OP 变得无关紧要,哈哈。
话虽这么说,正如任何人都可能看到的那样,有几个机会可以创建循环,这将大大减少重复代码的数量和要处理的代码数量,并且还可以支持任意数量的单词......
-- THIS SCRIPT WAS NOT INTENDED TO BE THE FINAL PRODUCT, BUT MAY END UP CLOSE
-- DGTTs AND MULTIPLE RESULT WINDOWS WERE INTENDED TO EXAMININE EACH STEP
-- UNCOMMENT ANY OF THE SELECT STATEMENTS TO SEE WHAT'S GOING ON THERE
-- THIS IS HARD-CODED TO PROCESS UP TO (9) WORDS
-- IF RE-WRITTEN WITH LOOPS, IT'D BE MORE COMPACT AND SUPPORT ANY NUMBER OF WORDS
DECLARE GLOBAL TEMPORARY TABLE SESSION.WORDS AS
( WITH PASS1 AS ( SELECT LPAD(TRIM(CHAR(BXUPCR)),14,'0') AS BXUPCR,
UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,1,'i'))) AS W1,
UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,2,'i'))) AS W2,
UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,3,'i'))) AS W3,
UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,4,'i'))) AS W4,
UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,5,'i'))) AS W5,
UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,6,'i'))) AS W6,
UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,7,'i'))) AS W7,
UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,8,'i'))) AS W8,
UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,9,'i'))) AS W9
FROM F_CERTOB.BEERXT AS BEERT
INNER JOIN F_CERTOB.INVENT AS INVEN ON BXITEM=IYITEM
WHERE BXPACK > 999
AND BXUPCR > 0
AND BXUM = 'CB'
AND IYWHSE = '1'
AND IYSTAT IN ('A','B')
)
--PASS #2: GROUP ITMES WITH IDENTICAL UPC & TEXT. THIS IS VERY FEW ITEMS OUT OF ALL.
SELECT BXUPCR, W1, W2, W3, W4, W5, W6, W7, W8, W9, COUNT(*) AS C
FROM PASS1
GROUP BY BXUPCR, W1, W2, W3, W4, W5, W6, W7, W8, W9
) WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.WORDS ORDER BY 1,2,3,4,5,6,7,8,9,10 @
--NUMBER OF ITEMS PER UPC
DECLARE GLOBAL TEMPORARY TABLE SESSION.WCNT AS
( SELECT BXUPCR, COUNT(BXUPCR) AS UPC_COUNT
FROM SESSION.WORDS
GROUP BY BXUPCR
) WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.WCNT ORDER BY 1 @
--FUNNEL CERTAIN ITEMS FOR TESTING ------------FOR DEV ONLY
--THIS CAN BE REMOVED AND PATCHED AROUND LATER
DECLARE GLOBAL TEMPORARY TABLE SESSION.FUNNEL AS
( SELECT A.BXUPCR, A.W1, A.W2, A.W3, A.W4, A.W5, A.W6, A.W7, A.W8, A.W9
FROM SESSION.WORDS AS A
INNER JOIN SESSION.WCNT AS B ON A.BXUPCR=B.BXUPCR
) WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.FUNNEL ORDER BY 1 @
--GROUPS OF (1) WORD:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP1 AS
( SELECT BXUPCR, W1, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 1 AS THIS_GROUP
FROM SESSION.FUNNEL
INNER JOIN SESSION.WCNT USING(BXUPCR)
WHERE (W1) IS NOT NULL
GROUP BY BXUPCR, W1, UPC_COUNT
HAVING UPC_COUNT = COUNT(*)
) WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP1 ORDER BY 1 @
--GROUPS OF (2) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP2 AS
( SELECT BXUPCR, W1, W2, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 2 AS THIS_GROUP
FROM SESSION.FUNNEL
INNER JOIN SESSION.WCNT USING(BXUPCR)
WHERE (W1 || W2) IS NOT NULL
GROUP BY BXUPCR, W1, W2, UPC_COUNT
HAVING UPC_COUNT = COUNT(*)
) WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP2 ORDER BY 1 @
--GROUPS OF (3) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP3 AS
( SELECT BXUPCR, W1, W2, W3, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 3 AS THIS_GROUP
FROM SESSION.FUNNEL
INNER JOIN SESSION.WCNT USING(BXUPCR)
WHERE (W1 || W2 || W3) IS NOT NULL
GROUP BY BXUPCR, W1, W2, W3, UPC_COUNT
HAVING UPC_COUNT = COUNT(*)
) WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP3 ORDER BY 1 @
--GROUPS OF (4) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP4 AS
( SELECT BXUPCR, W1, W2, W3, W4, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 4 AS THIS_GROUP
FROM SESSION.FUNNEL
INNER JOIN SESSION.WCNT USING(BXUPCR)
WHERE (W1 || W2 || W3 || W4) IS NOT NULL
GROUP BY BXUPCR, W1, W2, W3, W4, UPC_COUNT
HAVING UPC_COUNT = COUNT(*)
) WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP4 ORDER BY 1 @
--GROUPS OF (5) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP5 AS
( SELECT BXUPCR, W1, W2, W3, W4, W5, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 5 AS THIS_GROUP
FROM SESSION.FUNNEL
INNER JOIN SESSION.WCNT USING(BXUPCR)
WHERE (W1 || W2 || W3 || W4 || W5) IS NOT NULL
GROUP BY BXUPCR, W1, W2, W3, W4, W5, UPC_COUNT
HAVING UPC_COUNT = COUNT(*)
) WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP5 ORDER BY 1 @
--GROUPS OF (6) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP6 AS
( SELECT BXUPCR, W1, W2, W3, W4, W5, W6, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 6 AS THIS_GROUP
FROM SESSION.FUNNEL
INNER JOIN SESSION.WCNT USING(BXUPCR)
WHERE (W1 || W2 || W3 || W4 || W5 || W6) IS NOT NULL
GROUP BY BXUPCR, W1, W2, W3, W4, W5, W6, UPC_COUNT
HAVING UPC_COUNT = COUNT(*)
) WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP6 ORDER BY 1 @
--GROUPS OF (7) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP7 AS
( SELECT BXUPCR, W1, W2, W3, W4, W5, W6, W7, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 7 AS THIS_GROUP
FROM SESSION.FUNNEL
INNER JOIN SESSION.WCNT USING(BXUPCR)
WHERE (W1 || W2 || W3 || W4 || W5 || W6 || W7) IS NOT NULL
GROUP BY BXUPCR, W1, W2, W3, W4, W5, W6, W7, UPC_COUNT
HAVING UPC_COUNT = COUNT(*)
) WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP7 ORDER BY 1 @
--GROUPS OF (8) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP8 AS
( SELECT BXUPCR, W1, W2, W3, W4, W5, W6, W7, W8, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 8 AS THIS_GROUP
FROM SESSION.FUNNEL
INNER JOIN SESSION.WCNT USING(BXUPCR)
WHERE (W1 || W2 || W3 || W4 || W5 || W6 || W7 || W8) IS NOT NULL
GROUP BY BXUPCR, W1, W2, W3, W4, W5, W6, W7, W8, UPC_COUNT
HAVING UPC_COUNT = COUNT(*)
) WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP8 ORDER BY 1 @
--GROUPS OF (9) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP9 AS
( SELECT BXUPCR, W1, W2, W3, W4, W5, W6, W7, W8, W9, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 9 AS THIS_GROUP
FROM SESSION.FUNNEL
INNER JOIN SESSION.WCNT USING(BXUPCR)
WHERE (W1 || W2 || W3 || W4 || W5 || W6 || W7 || W8 || W9) IS NOT NULL
GROUP BY BXUPCR, W1, W2, W3, W4, W5, W6, W7, W8, W9, UPC_COUNT
HAVING UPC_COUNT = COUNT(*)
) WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP9 ORDER BY 1 @
--MERGE EVERYTHING TOGETHER:
DECLARE GLOBAL TEMPORARY TABLE SESSION.UNIONX AS
( SELECT BXUPCR, W1 AS W1, '' AS W2, '' AS W3, '' AS W4, '' AS W5, '' AS W6, '' AS W7, '' AS W8, '' AS W9, 1 AS WC
FROM SESSION.GRP1
UNION
SELECT BXUPCR, W1 AS W1, W2 AS W2, '' AS W3, '' AS W4, '' AS W5, '' AS W6, '' AS W7, '' AS W8, '' AS W9, 2 AS WC
FROM SESSION.GRP2
UNION
SELECT BXUPCR, W1 AS W1, W2 AS W2, W3 AS W3, '' AS W4, '' AS W5, '' AS W6, '' AS W7, '' AS W8, '' AS W9, 3 AS WC
FROM SESSION.GRP3
UNION
SELECT BXUPCR, W1 AS W1, W2 AS W2, W3 AS W3, W4 AS W4, '' AS W5, '' AS W6, '' AS W7, '' AS W8, '' AS W9, 4 AS WC
FROM SESSION.GRP4
UNION
SELECT BXUPCR, W1 AS W1, W2 AS W2, W3 AS W3, W4 AS W4, W5 AS W5, '' AS W6, '' AS W7, '' AS W8, '' AS W9, 5 AS WC
FROM SESSION.GRP5
UNION
SELECT BXUPCR, W1 AS W1, W2 AS W2, W3 AS W3, W4 AS W4, W5 AS W5, W6 AS W6, '' AS W7, '' AS W8, '' AS W9, 6 AS WC
FROM SESSION.GRP6
UNION
SELECT BXUPCR, W1 AS W1, W2 AS W2, W3 AS W3, W4 AS W4, W5 AS W5, W6 AS W6, W7 AS W7, '' AS W8, '' AS W9, 7 AS WC
FROM SESSION.GRP7
UNION
SELECT BXUPCR, W1 AS W1, W2 AS W2, W3 AS W3, W4 AS W4, W5 AS W5, W6 AS W6, W7 AS W7, W8 AS W8, '' AS W9, 8 AS WC
FROM SESSION.GRP8
UNION
SELECT BXUPCR, W1 AS W1, W2 AS W2, W3 AS W3, W4 AS W4, W5 AS W5, W6 AS W6, W7 AS W7, W8 AS W8, W9 AS W9, 9 AS WC
FROM SESSION.GRP9
GROUP BY BXUPCR, W1, W2, W3, W4, W5, W6, W7, W8, W9
) WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.UNIONX ORDER BY BXUPCR,W1,W2,W3,W4,W5,W6,W7,W8,W9 @
--FINAL RESULT:
DECLARE GLOBAL TEMPORARY TABLE SESSION.PICKER AS
( SELECT BXUPCR, TRIM(W1 || ' ' || W2 || ' ' || W3 || ' ' || W4 || ' ' || W5 || ' ' || W6 || ' ' || W7 || ' ' || W8 || ' ' || W9) AS WORDS
FROM SESSION.UNIONX
INNER JOIN TABLE( SELECT BXUPCR, MAX(WC) AS WC
FROM SESSION.UNIONX
GROUP BY BXUPCR
) AS TMP USING(BXUPCR, WC)
) WITH DATA WITH REPLACE @
SELECT * FROM SESSION.PICKER ORDER BY 1 @
【问题讨论】:
-
DGTT 可以作为正常插入/选择/等的一部分并行访问,就像任何其他表一样,因此任何语句都可以像往常一样按行并行化。因此,您还通常希望避免显式循环。我们可以更详细地了解您在这里要完成的工作吗?
-
我在我的 OP 末尾添加了一个示例。
-
你有一个问题 - 如果单词在同一 UPC 的两个实例中的顺序不同,它们将是不同的行。更一般地,您希望单词在相同数量的单词中具有相同的顺序。
BXADDS代表什么?如果它是一个以空格分隔的值列表(违反正常形式不是很好),那么您最好的选择可能是定义一个表函数来吐出单词行。 (这在 LUW 上会更容易)。这几乎会自动让您获得无限的单词(并且旋转也会更容易一些)。 -
BXADDS 是作为人类可读标题的产品描述,例如“Mike's Harder Black Cherry Lemonade”。我们很擅长保持单词的正确顺序;我们必须,否则我们的 50 多名路线销售人员会冲我们大喊他们没有在产品列表中正确显示/排序。另外,您给了我另一个想法:如果单词很常见,但出现在不同的位置怎么办?比如“Mike's Harder Black Cherry Lemonade”和“Mike's Harder Watermelon Lemonade”..?常见的词是“Mike's Harder Lemonade”;中间的唯一词被跳过。
-
...您实际上想要在这里完成什么?你需要这些信息是为了什么?如果您只想查询与某组词匹配的所有产品,那么您正在查看某种类型的全文搜索(DB2 for i 可能具有一些本机功能)。如果您试图为报告之类的内容找到通用元素,则无法避免拆分 (An example using a recursive CTE),但您可能可以执行一些操作,例如将拆分缓存到永久标签表中。