使用动态更新查询更新 Ledger_stat table 中的天数列值
Updating day number columns' values in Ledger_stat table using dynamic update query
我有一个 table LEDGER_STAT_DLY
,其中我们有一个月中每一天的列 (DAY_01
是第 1 天,DAY_02
,...., DAY_31)。目前,我正在使用 case 语句更新 Day
列的值,如下所示。
CASE DAY(V_DATE)
WHEN 1 THEN
UPDATE /*+ index(a LEDGER_STAT_DLY_IDX02_IN) */ LEDGER_STAT_DLY A
SET DAY_01 = NVL(DAY_01,0) + NVL(V_AMOUNT,0)
WHERE IDENTITY_CODE = NVL(V_IDENTITY_CODE,0)
AND YEAR_S = NVL(V_YEAR_S,0)
AND MONTH_NO = NVL(V_MONTH,0)
AND CONSOLIDATION_CD = NVL(V_CONSOLIDATION_CD,0)
AND FINANCIAL_ELEM_ID = NVL(V_FINANCIAL_ELEM_ID,0)
AND ORG_UNIT_ID = NVL(V_ORG_UNIT_ID,0)
AND GL_ACCOUNT_ID = NVL(V_GL_ACCOUNT_ID,0)
AND COMMON_COA_ID = NVL(V_COMMON_COA_ID,0)
AND PRODUCT_1_ID = NVL(V_PRODUCT_1_ID,0)
AND PRODUCT_ID = NVL(V_PRODUCT_ID,0)
AND PRODUCT_3_ID = NVL(V_PRODUCT_3_ID,0)
AND COST_TYPE_ID = NVL(V_MEMO_GL_ACCOUNT_ID,0)
AND BALANCE_TYPE_CD = NVL(V_BALANCE_TYPE_CD,0);
WHEN 2 THEN
UPDATE /*+ index(a LEDGER_STAT_DLY_IDX02_IN) */ LEDGER_STAT_DLY A
SET DAY_02 = NVL(DAY_02,0) + NVL(V_AMOUNT,0)
WHERE IDENTITY_CODE = NVL(V_IDENTITY_CODE,0)
AND YEAR_S = NVL(V_YEAR_S,0)
AND MONTH_NO = NVL(V_MONTH,0)
AND CONSOLIDATION_CD = NVL(V_CONSOLIDATION_CD,0)
AND FINANCIAL_ELEM_ID = NVL(V_FINANCIAL_ELEM_ID,0)
AND ORG_UNIT_ID = NVL(V_ORG_UNIT_ID,0)
AND GL_ACCOUNT_ID = NVL(V_GL_ACCOUNT_ID,0)
AND COMMON_COA_ID = NVL(V_COMMON_COA_ID,0)
AND PRODUCT_1_ID = NVL(V_PRODUCT_1_ID,0)
AND PRODUCT_ID = NVL(V_PRODUCT_ID,0)
AND PRODUCT_3_ID = NVL(V_PRODUCT_3_ID,0)
AND COST_TYPE_ID = NVL(V_MEMO_GL_ACCOUNT_ID,0)
AND BALANCE_TYPE_CD = NVL(V_BALANCE_TYPE_CD,0);
-- and so forth, I have written 31 blocks
虽然工作正常,但是程序中的代码超长。您能否建议我如何使用动态查询更新它,以便此代码减少到更少的 lines/single 块而不是 31 个单独的 case 语句。
在此先感谢您的帮助!
PS:正在使用 day()
函数从 V_DATE
中提取日期。逻辑是,每当 day(v_date)
匹配 LEDGER_STAT_DLY
table 的 day_number(01, 02,03...)
列时,相应地更新该列的值。
抱歉这么说,但最好的办法是规范化此 table,摆脱重复的 DAY_01
、DAY_02
等字段。这将使您的工作变得非常简单。
显然你的table目前看起来像
CREATE TABLE LEDGER_STAT_DLY
(IDENTITY_CODE NUMBER,
YEAR_S NUMBER,
MONTH_NO NUMBER,
CONSOLIDATION_CD NUMBER,
FINANCIAL_ELEM_ID NUMBER,
ORG_UNIT_ID NUMBER,
GL_ACCOUNT_ID NUMBER,
COMMON_COA_ID NUMBER,
PRODUCT_ID NUMBER,
PRODUCT_1_ID NUMBER,
PRODUCT_3_ID NUMBER,
COST_TYPE_ID NUMBER,
BALANCE_TYPE_CD NUMBER,
DAY_01 NUMBER,
DAY_02 NUMBER,
...
DAY_31 NUMBER);
我建议将其替换为
CREATE TABLE LEDGER_STAT_DLY
(IDENTITY_CODE NUMBER,
YEAR_S NUMBER,
MONTH_NO NUMBER,
CONSOLIDATION_CD NUMBER,
FINANCIAL_ELEM_ID NUMBER,
ORG_UNIT_ID NUMBER,
GL_ACCOUNT_ID NUMBER,
COMMON_COA_ID NUMBER,
PRODUCT_ID NUMBER,
PRODUCT_1_ID NUMBER,
PRODUCT_3_ID NUMBER,
COST_TYPE_ID NUMBER,
BALANCE_TYPE_CD NUMBER,
DAY_NUMBER NUMBER,
DAY_VALUE NUMBER);
DAY_NUMBER
成为一个月中的第几天,因此它的值为 1 - 31。DAY_VALUE
被分配用于进入 DAY_01 的值,DAY_02, 等等。如果你想一想你正在编写重复代码块来处理所有单独的 DAY_xx 字段的所有地方,你就会意识到这种规范化结构处理起来有多么容易.
我同意 Bob Jarvis 的回答中表达的观点,但如果重构基础 table 不适合您,则可以使用动态 SQL 来完成。
您提供的示例中似乎有一个变量(DAY_01
/DAY_02
/DAY_03
... 字段)需要在两个地方使用。所以这个字段需要替换成静态语句的其余部分。
下面是一个例子。
首先,添加一个变量来保存目标字段名称。 (这并不是真正必需的,只是为了便于阅读)。
由于在 day-number 1,2,3 和字段 DAY_01
、DAY_02
、DAY_03
之间存在有序转换,这可以在直接分配中确定。
然后在当前开关为 in-use 的过程主体中,您可以使用 EXECUTE IMMEDIATE
,替换(通过连接或像 UTL_LMS
这样的字符串格式化程序)column-name 在带有目标 DAY_01
、DAY_02
等的语句中,其中 column-name 在语句中。
CREATE OR REPLACE PROCEDURE UPDATE_LEDGER_STAT_DLY(V_IDENTITY_CODE NUMBER,
V_CONSOLIDATION_CD NUMBER,
V_FINANCIAL_ELEM_ID NUMBER,
V_ORG_UNIT_ID NUMBER,
V_GL_ACCOUNT_ID NUMBER,
V_COMMON_COA_ID NUMBER,
V_PRODUCT_1_ID NUMBER,
V_PRODUCT_ID NUMBER,
V_PRODUCT_3_ID NUMBER,
V_DATE DATE,
V_AMOUNT NUMBER,
V_MEMO_GL_ACCOUNT_ID NUMBER DEFAULT 0,
V_POSTINGTYPE CHAR DEFAULT 'N',
V_BALANCE_TYPE_CD NUMBER DEFAULT 0)
IS
V_CNT NUMBER;
V_D NUMBER;
V_DAY CHAR(6);
V_MONTH CHAR(2);
V_MO NUMBER;
V_YEAR_S NUMBER;
BEGIN
IF V_POSTINGTYPE = 'N' THEN
IF NVL(V_AMOUNT, 0) <> 0 THEN
V_MO := (MONTH(V_DATE));
V_MONTH := LPAD(V_MO, 2, '0');
V_YEAR_S := (YEAR(V_DATE));
V_D := (DAY(V_DATE));
V_DAY := 'DAY_' || lpad(V_D, 2, '0');
EXECUTE IMMEDIATE UTL_LMS.FORMAT_MESSAGE('UPDATE /*+ index(a LEDGER_STAT_DLY_IDX02_IN) */ LEDGER_STAT_DLY A
SET %s = NVL(%s,0) + NVL(:THE_AMOUNT,0)
WHERE IDENTITY_CODE = NVL(:THE_IDENTITY_CODE,0)
AND YEAR_S = NVL(:THE_YEAR_S,0)
AND MONTH_NO = NVL(:THE_MONTH,0)
AND CONSOLIDATION_CD = NVL(:THE_CONSOLIDATION_CD,0)
AND FINANCIAL_ELEM_ID = NVL(:THE_FINANCIAL_ELEM_ID,0)
AND ORG_UNIT_ID = NVL(:ORG_UNIT_ID,0)
AND GL_ACCOUNT_ID = NVL(:THE_GL_ACCOUNT_ID,0)
AND COMMON_COA_ID = NVL(:THE_COMMON_COA_ID,0)
AND PRODUCT_1_ID = NVL(:THE_PRODUCT_1_ID,0)
AND PRODUCT_ID = NVL(:THE_PRODUCT_ID,0)
AND PRODUCT_3_ID = NVL(:THE_PRODUCT_3_ID,0)
AND COST_TYPE_ID = NVL(:THE_MEMO_GL_ACCOUNT_ID,0)
AND BALANCE_TYPE_CD = NVL(:THE_BALANCE_TYPE_CD,0)', V_DAY, V_DAY)
USING V_AMOUNT, V_IDENTITY_CODE, V_YEAR_S, V_MONTH, V_CONSOLIDATION_CD,
V_FINANCIAL_ELEM_ID, V_ORG_UNIT_ID, V_GL_ACCOUNT_ID,
V_COMMON_COA_ID, V_PRODUCT_1_ID, V_PRODUCT_ID, V_PRODUCT_3_ID, V_MEMO_GL_ACCOUNT_ID, V_BALANCE_TYPE_CD;
END IF;
END IF;
END;
/
我有一个 table LEDGER_STAT_DLY
,其中我们有一个月中每一天的列 (DAY_01
是第 1 天,DAY_02
,...., DAY_31)。目前,我正在使用 case 语句更新 Day
列的值,如下所示。
CASE DAY(V_DATE)
WHEN 1 THEN
UPDATE /*+ index(a LEDGER_STAT_DLY_IDX02_IN) */ LEDGER_STAT_DLY A
SET DAY_01 = NVL(DAY_01,0) + NVL(V_AMOUNT,0)
WHERE IDENTITY_CODE = NVL(V_IDENTITY_CODE,0)
AND YEAR_S = NVL(V_YEAR_S,0)
AND MONTH_NO = NVL(V_MONTH,0)
AND CONSOLIDATION_CD = NVL(V_CONSOLIDATION_CD,0)
AND FINANCIAL_ELEM_ID = NVL(V_FINANCIAL_ELEM_ID,0)
AND ORG_UNIT_ID = NVL(V_ORG_UNIT_ID,0)
AND GL_ACCOUNT_ID = NVL(V_GL_ACCOUNT_ID,0)
AND COMMON_COA_ID = NVL(V_COMMON_COA_ID,0)
AND PRODUCT_1_ID = NVL(V_PRODUCT_1_ID,0)
AND PRODUCT_ID = NVL(V_PRODUCT_ID,0)
AND PRODUCT_3_ID = NVL(V_PRODUCT_3_ID,0)
AND COST_TYPE_ID = NVL(V_MEMO_GL_ACCOUNT_ID,0)
AND BALANCE_TYPE_CD = NVL(V_BALANCE_TYPE_CD,0);
WHEN 2 THEN
UPDATE /*+ index(a LEDGER_STAT_DLY_IDX02_IN) */ LEDGER_STAT_DLY A
SET DAY_02 = NVL(DAY_02,0) + NVL(V_AMOUNT,0)
WHERE IDENTITY_CODE = NVL(V_IDENTITY_CODE,0)
AND YEAR_S = NVL(V_YEAR_S,0)
AND MONTH_NO = NVL(V_MONTH,0)
AND CONSOLIDATION_CD = NVL(V_CONSOLIDATION_CD,0)
AND FINANCIAL_ELEM_ID = NVL(V_FINANCIAL_ELEM_ID,0)
AND ORG_UNIT_ID = NVL(V_ORG_UNIT_ID,0)
AND GL_ACCOUNT_ID = NVL(V_GL_ACCOUNT_ID,0)
AND COMMON_COA_ID = NVL(V_COMMON_COA_ID,0)
AND PRODUCT_1_ID = NVL(V_PRODUCT_1_ID,0)
AND PRODUCT_ID = NVL(V_PRODUCT_ID,0)
AND PRODUCT_3_ID = NVL(V_PRODUCT_3_ID,0)
AND COST_TYPE_ID = NVL(V_MEMO_GL_ACCOUNT_ID,0)
AND BALANCE_TYPE_CD = NVL(V_BALANCE_TYPE_CD,0);
-- and so forth, I have written 31 blocks
虽然工作正常,但是程序中的代码超长。您能否建议我如何使用动态查询更新它,以便此代码减少到更少的 lines/single 块而不是 31 个单独的 case 语句。 在此先感谢您的帮助!
PS:正在使用 day()
函数从 V_DATE
中提取日期。逻辑是,每当 day(v_date)
匹配 LEDGER_STAT_DLY
table 的 day_number(01, 02,03...)
列时,相应地更新该列的值。
抱歉这么说,但最好的办法是规范化此 table,摆脱重复的 DAY_01
、DAY_02
等字段。这将使您的工作变得非常简单。
显然你的table目前看起来像
CREATE TABLE LEDGER_STAT_DLY
(IDENTITY_CODE NUMBER,
YEAR_S NUMBER,
MONTH_NO NUMBER,
CONSOLIDATION_CD NUMBER,
FINANCIAL_ELEM_ID NUMBER,
ORG_UNIT_ID NUMBER,
GL_ACCOUNT_ID NUMBER,
COMMON_COA_ID NUMBER,
PRODUCT_ID NUMBER,
PRODUCT_1_ID NUMBER,
PRODUCT_3_ID NUMBER,
COST_TYPE_ID NUMBER,
BALANCE_TYPE_CD NUMBER,
DAY_01 NUMBER,
DAY_02 NUMBER,
...
DAY_31 NUMBER);
我建议将其替换为
CREATE TABLE LEDGER_STAT_DLY
(IDENTITY_CODE NUMBER,
YEAR_S NUMBER,
MONTH_NO NUMBER,
CONSOLIDATION_CD NUMBER,
FINANCIAL_ELEM_ID NUMBER,
ORG_UNIT_ID NUMBER,
GL_ACCOUNT_ID NUMBER,
COMMON_COA_ID NUMBER,
PRODUCT_ID NUMBER,
PRODUCT_1_ID NUMBER,
PRODUCT_3_ID NUMBER,
COST_TYPE_ID NUMBER,
BALANCE_TYPE_CD NUMBER,
DAY_NUMBER NUMBER,
DAY_VALUE NUMBER);
DAY_NUMBER
成为一个月中的第几天,因此它的值为 1 - 31。DAY_VALUE
被分配用于进入 DAY_01 的值,DAY_02, 等等。如果你想一想你正在编写重复代码块来处理所有单独的 DAY_xx 字段的所有地方,你就会意识到这种规范化结构处理起来有多么容易.
我同意 Bob Jarvis 的回答中表达的观点,但如果重构基础 table 不适合您,则可以使用动态 SQL 来完成。
您提供的示例中似乎有一个变量(DAY_01
/DAY_02
/DAY_03
... 字段)需要在两个地方使用。所以这个字段需要替换成静态语句的其余部分。
下面是一个例子。
首先,添加一个变量来保存目标字段名称。 (这并不是真正必需的,只是为了便于阅读)。
由于在 day-number 1,2,3 和字段 DAY_01
、DAY_02
、DAY_03
之间存在有序转换,这可以在直接分配中确定。
然后在当前开关为 in-use 的过程主体中,您可以使用 EXECUTE IMMEDIATE
,替换(通过连接或像 UTL_LMS
这样的字符串格式化程序)column-name 在带有目标 DAY_01
、DAY_02
等的语句中,其中 column-name 在语句中。
CREATE OR REPLACE PROCEDURE UPDATE_LEDGER_STAT_DLY(V_IDENTITY_CODE NUMBER,
V_CONSOLIDATION_CD NUMBER,
V_FINANCIAL_ELEM_ID NUMBER,
V_ORG_UNIT_ID NUMBER,
V_GL_ACCOUNT_ID NUMBER,
V_COMMON_COA_ID NUMBER,
V_PRODUCT_1_ID NUMBER,
V_PRODUCT_ID NUMBER,
V_PRODUCT_3_ID NUMBER,
V_DATE DATE,
V_AMOUNT NUMBER,
V_MEMO_GL_ACCOUNT_ID NUMBER DEFAULT 0,
V_POSTINGTYPE CHAR DEFAULT 'N',
V_BALANCE_TYPE_CD NUMBER DEFAULT 0)
IS
V_CNT NUMBER;
V_D NUMBER;
V_DAY CHAR(6);
V_MONTH CHAR(2);
V_MO NUMBER;
V_YEAR_S NUMBER;
BEGIN
IF V_POSTINGTYPE = 'N' THEN
IF NVL(V_AMOUNT, 0) <> 0 THEN
V_MO := (MONTH(V_DATE));
V_MONTH := LPAD(V_MO, 2, '0');
V_YEAR_S := (YEAR(V_DATE));
V_D := (DAY(V_DATE));
V_DAY := 'DAY_' || lpad(V_D, 2, '0');
EXECUTE IMMEDIATE UTL_LMS.FORMAT_MESSAGE('UPDATE /*+ index(a LEDGER_STAT_DLY_IDX02_IN) */ LEDGER_STAT_DLY A
SET %s = NVL(%s,0) + NVL(:THE_AMOUNT,0)
WHERE IDENTITY_CODE = NVL(:THE_IDENTITY_CODE,0)
AND YEAR_S = NVL(:THE_YEAR_S,0)
AND MONTH_NO = NVL(:THE_MONTH,0)
AND CONSOLIDATION_CD = NVL(:THE_CONSOLIDATION_CD,0)
AND FINANCIAL_ELEM_ID = NVL(:THE_FINANCIAL_ELEM_ID,0)
AND ORG_UNIT_ID = NVL(:ORG_UNIT_ID,0)
AND GL_ACCOUNT_ID = NVL(:THE_GL_ACCOUNT_ID,0)
AND COMMON_COA_ID = NVL(:THE_COMMON_COA_ID,0)
AND PRODUCT_1_ID = NVL(:THE_PRODUCT_1_ID,0)
AND PRODUCT_ID = NVL(:THE_PRODUCT_ID,0)
AND PRODUCT_3_ID = NVL(:THE_PRODUCT_3_ID,0)
AND COST_TYPE_ID = NVL(:THE_MEMO_GL_ACCOUNT_ID,0)
AND BALANCE_TYPE_CD = NVL(:THE_BALANCE_TYPE_CD,0)', V_DAY, V_DAY)
USING V_AMOUNT, V_IDENTITY_CODE, V_YEAR_S, V_MONTH, V_CONSOLIDATION_CD,
V_FINANCIAL_ELEM_ID, V_ORG_UNIT_ID, V_GL_ACCOUNT_ID,
V_COMMON_COA_ID, V_PRODUCT_1_ID, V_PRODUCT_ID, V_PRODUCT_3_ID, V_MEMO_GL_ACCOUNT_ID, V_BALANCE_TYPE_CD;
END IF;
END IF;
END;
/