EDIT: I've added more at the end of the original question.
[Original question]:
In a DB2 SQL table function, can the scope of a declared global temporary table be limited to the current instance of the function..? This is DB2-for-i v7r3m0.
I'm planning a table function for analysis of character data. To do its thing, the function needs a temporary table in which to cache information which will then be repeatedly looped through in different ways until a result is reached. My first thought was to use a declared global temporary table, but there's that word "global".
For greater efficiency, I'd like to write the function with ALLOW PARALLEL
, and possibly NOT FENCED
, but these two options seem to be in conflict with the nature of a DGTT.
Also, because MODIFIES SQL DATA
is needed to write to a DGTT, I'm not sure if there's any way I can use ALLOW PARALLEL
, even with careful design of the function.
The documentation confuses me a bit; perhaps I'm not understanding something? In the opening paragraph it says:
Each application process that defines a declared temporary table of the same name has its own unique description of the temporary table.
And then under table-name
it says:
If a declared temporary table, or an index or view that is dependent on a declared temporary table already exists with the same name, an error is returned.
So I would like to ask: can a DGTT or any other type of temporary table be created so its scope is limited only to the current instance of the function..?
I could muddle about with random names for the DGTT, but that would complexify the code a bit. Ideally I'd like to just use one name.
Another thought I had was to have a set of key columns in the DGTT that are populated by the input parameters of the function. Then all instances of the function could share one DGTT, but would only access their own rows.
Does anyone have any suggestions..?
EDIT:
Ok, I've worked on this for two days straight, and finally created a working example. There is an obvious excess of DGTTs; these were originally CTEs, but I converted them all for development to allow a result window after each step of the process.
And what started with the intention of being a scalar function with one input parameter, and one output, I think it could very satisfactorily be a table function with no input parameters.
What I ended up with turned out pretty efficient, and MUCH faster than my first couple of tries. In fact, I could very easily keep this as-is, but I would convert the DGTTs back to CTEs to see if there's any change in efficiency. Its possibly I would see no change, in which case there would be no DGTTs would thus would make my whole OP irrelevant, lol.
That being said, as anyone might see, there are a couple of opportunities to create loops that would greatly reduce the amount of repetitive code & the amount of code to process, and would also support any number of words...
-- 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 @