Db2 for i - 动态FROM子句

问题描述 投票:1回答:2

环境:Db2 for i, version 7.3

图书馆/桌子结构:

CORPORATE/TENANTS
LIB01/INVOICE
LIB02/INVOICE
LIB03/INVOICE
…
LIBxx/INVOICE

CORPORATE/TENANTS表包含一个库列表,其中存储有关每个租户的信息。它有这种结构和数据:

CREATE OR REPLACE TABLE TENANTS (
ID     BIGINT GENERATED ALWAYS AS IDENTITY (START WITH 1),
TENANT CHAR(10) NOT NULL,
PRIMARY KEY(ID)
) RCDFMT TENANTSR;

RUNSQLSTM SRCFILE(HILLB/QDDLSRC) SRCMBR(TENANTS) DFTRDBCOL(CORPORATE)

+--+------+
|ID|TENANT|
+--+------+
| 1|LIB01 |
| 2|LIB02 |
|..|......|
|99|LIB99 |
+--+------+

LIBxx/INVOICE表彼此完全相同,并具有以下结构:

CREATE OR REPLACE TABLE INVOICE (
ID     BIGINT GENERATED ALWAYS AS IDENTITY (START WITH 1),
PAYDAT INTEGER(6,0) NOT NULL,
AMOUNT DECIMAL(15,2) NOT NULL DEFAULT 0,
PRIMARY KEY(ID)
) RCDFMT INVOICER;

+--+------+------+
|ID|PAYDAT|AMOUNT|
+--+------+------+
| 1|180701|100.00|
| 2|180801| 35.00|
|..|......|......|
+--+------+------+

我想为给定日期生成所有租户的发票金额列表:

180701 LIB01 100.00
180701 LIB02 140.00
180701 LIB03  74.00
…

从概念上讲,我想要做的就是这个(是的,我知道这是无效的SQL):

SELECT PAYDAT, TENANT, AMOUNT
FROM $X.INVOICE
WHERE PAYDAT = 180701;

我想从INVOICE表中为每个TENANT提取数据,但我知道FROM子句不能像这样动态。我确定这种查询有一个名字,但我不知道它是什么,所以我无法有效地使用搜索引擎找到我需要的东西。

使用RPGLE程序解决这个问题很简单,但我需要一个纯SQL解决方案。

请注意 - LIBxx值不能以任何方式进行硬编码。这些值可以随时更改。

sql ibm-midrange db2-400
2个回答
1
投票

要做你想做的事,你可以在循环中使用带有EXECUTE IMMEDIATE的存储过程来构建结果集。像这样的东西:

注意:这不是一个完整的剪切和粘贴解决方案,但您可以修改它以执行您想要的操作。

CREATE OR REPLACE PROCEDURE GETINVOICEAMOUNTS ( ) 
  DYNAMIC RESULT SETS 1 
  LANGUAGE SQL 
  NOT DETERMINISTIC 
  MODIFIES SQL DATA 
  CALLED ON NULL INPUT 
  SET OPTION COMMIT = *NONE
BEGIN
  DECLARE STMT VARCHAR(1024);
  DECLARE RECORD_FOUND INTEGER DEFAULT 1;
  DECLARE LIBRARY CHAR(10);
  DECLARE C1 CURSOR FOR
    SELECT TENANT FROM CORPORATE/TENANT;
  DECLARE C2 CURSOR WITH RETURN FOR 
    SELECT * FROM SESSION.TMP ; 
  DECLARE CONTINUE HANDLER FOR NOT FOUND
    SET RECORD_FOUND = 0;
  DECLARE GLOBAL TEMPORARY TABLE TMP 
    (PAYDAT INTEGER(6,0),
     TENANT CHAR(10),
     AMOUNT DECIMAL(15,2))
    WITH REPLACE;
  OPEN C1;
  LOOP
    FETCH C1 INTO LIBRARY;
    IF RECORD_FOUND = 0;
      LEAVE LOOP;
    END IF;        
    SET STMT = 'INSERT INTO SESSION.TMP SELECT PAYDAT, LIBRARY, AMOUNT FROM ' || RTRIM(LIBRARY) || '.INVOICE WHERE PAYDAT = 180701';
    EXECUTE IMMEDIATE STMT
  END LOOP;
  CLOSE C1;
  OPEN C2; 
END; 

我给了你超过我的计划。但是,您总是需要的一个特定修改是参数化您要检索的日期。

这是它的工作原理:名为TMP的全局临时表用于收集要在结果集中返回的记录。收集完所有记录后,将在TMP上打开游标,程序结束。这会导致TMP中收集的值作为结果集返回。

要收集值,请读取CORPORATE/TENANT文件,并将列TENANT检索到变量LIBRARY中。对于每条记录,都会构建一个语句,将LIBRARY连接到INSERT语句中。执行此语句将记录加载到TMP中。我正在使用EXECUTE IMMEDIATE因为我不能使用参数标记来替换INSERT语句中的表引用,所以准备好的语句只是额外的工作。


0
投票

你可以使用UNION ALL

SELECT sub.PAYDAT, t.TENANT, sub.AMOUNT
FROM (SELECT * FROM LIB01.INVOICE
      UNION ALL
      SELECT * FROM LIB02/INVOICE
      ...
      SELECT * FROM LIB0n/INVOICE) sub
JOIN TENANTS t
  ON sub.id = t.id
WHERE SUB.PAYDAT = 180701;

这是一个SELECT * FROM sales + @yymm模板。


编辑:

更安全的方法是创建一个视图:

CREATE VIEW combined_invoice
AS
SELECT * FROM LIB01.INVOICE
UNION ALL
SELECT * FROM LIB02/INVOICE
...
SELECT * FROM LIB0n/INVOICE;

并查询:

SELECT sub.PAYDAT, t.TENANT, sub.AMOUNT
FROM combined_invoice sub
JOIN TENANTS t
  ON sub.id = t.id
WHERE SUB.PAYDAT = 180701;

当然,添加/删除表后应该更改视图。

© www.soinside.com 2019 - 2024. All rights reserved.