Oracle存储过程和游标

Oracle存储过程和游标,oracle,plsql,oracle11g,Oracle,Plsql,Oracle11g,我正在尝试编写一个存储过程来转换: |----------|----------|----------|----------|----------| | ID | ESD | TD | IS_DB | TEST_SET | |----------|----------|----------|----------|----------| | 1 | 10 | 20 | 1 | 2 | |

我正在尝试编写一个存储过程来转换:

|----------|----------|----------|----------|----------|
|    ID    |   ESD    |  TD      |   IS_DB  | TEST_SET |
|----------|----------|----------|----------|----------|
|    1     |  10      |  20      |    1     |    2     |
|    2     |  30      |  (null)  |    1     |    2     |
|    3     |  40      |  (null)  |    1     |    2     |
|    4     |  50      |  60      |    0     |    2     |
|    5     |  (null)  |  70      |    1     |    2     |
|    6     |  75      |  100     |    1     |    2     |
|    7     |  (null)  |  80      |    1     |    2     |
|----------|----------|----------|----------|----------|
为此:

|----------|----------|
|  DT      |  FLAG    |
|----------|----------|
|  10      |  E       |
|  20      |  H       |
|  30      |  E       |
|  40      |  E       |
|  50      |  E       |
|  60      |  S       |
|  70      |  H       |
|  75      |  E       |
|  80      |  H       |
|  100     |  H       |
|----------|----------|
业务规则是:

对于
测试数据\u SOVLP
中的每一行:

  • 如果当前的
    ESD
    值不是
    null
    ,则:

    • 在TEMP中插入一行,其值为:
      E
  • 如果当前
    TD
    值不是
    null
    ,则:

    • 如果
      为_DB=0
      =>请在TEMP中插入以下值:
      S
    • 如果
      为\u DB=1
      =>请在TEMP中插入以下值:
      H
  • 但我没有得到任何接近我期望的东西:

    • 临时表中没有写入任何内容
    • 控制台显示的值对我来说毫无意义:

      20小时 10 E 20小时 10 E 20小时

    问题

  • 有人能告诉我我在程序中做错了什么吗

  • 为什么没有数据存储在TEMP中

  • 有什么更干净的方法可以解决这个问题? 我尝试使用SQL查询(请参阅),但没有成功。 注意:我有多个类似的proc要编写,然后我想从一个“主”proc调用它来总结逻辑

  • 多谢各位

    1。存储某些数据的表

    CREATE TABLE "TEST_DATA_SOVLP" 
       (    "ID" NUMBER,
       "ESD" NUMBER, 
        "TD" NUMBER, 
        "IS_DB" NUMBER(1,0) DEFAULT 0, 
        "TEST_SET" NUMBER
       )
    
    INSERT INTO "TEST_DATA_SOVLP" (ID, ESD, TD, IS_DB, TEST_SET) VALUES ('1', '10', '20', '1', '2');
    INSERT INTO "TEST_DATA_SOVLP" (ID, ESD, IS_DB, TEST_SET) VALUES ('2', '30', '1', '2');
    INSERT INTO "TEST_DATA_SOVLP" (ID, ESD, IS_DB, TEST_SET) VALUES ('3', '40', '1', '2');
    INSERT INTO "TEST_DATA_SOVLP" (ID, ESD, TD, IS_DB, TEST_SET) VALUES ('4', '50', '60', '1', '2');
    INSERT INTO "TEST_DATA_SOVLP" (ID, TD, IS_DB, TEST_SET) VALUES ('5', '70', '1', '2');
    INSERT INTO "TEST_DATA_SOVLP" (ID, ESD, TD, IS_DB,TEST_SET) VALUES ('6', '75', '100', '1', '2');
    INSERT INTO "TEST_DATA_SOVLP" (ID, TD, IS_DB, TEST_SET) VALUES ('7', '80', '1', '2');
    
    一些数据

    CREATE TABLE "TEST_DATA_SOVLP" 
       (    "ID" NUMBER,
       "ESD" NUMBER, 
        "TD" NUMBER, 
        "IS_DB" NUMBER(1,0) DEFAULT 0, 
        "TEST_SET" NUMBER
       )
    
    INSERT INTO "TEST_DATA_SOVLP" (ID, ESD, TD, IS_DB, TEST_SET) VALUES ('1', '10', '20', '1', '2');
    INSERT INTO "TEST_DATA_SOVLP" (ID, ESD, IS_DB, TEST_SET) VALUES ('2', '30', '1', '2');
    INSERT INTO "TEST_DATA_SOVLP" (ID, ESD, IS_DB, TEST_SET) VALUES ('3', '40', '1', '2');
    INSERT INTO "TEST_DATA_SOVLP" (ID, ESD, TD, IS_DB, TEST_SET) VALUES ('4', '50', '60', '1', '2');
    INSERT INTO "TEST_DATA_SOVLP" (ID, TD, IS_DB, TEST_SET) VALUES ('5', '70', '1', '2');
    INSERT INTO "TEST_DATA_SOVLP" (ID, ESD, TD, IS_DB,TEST_SET) VALUES ('6', '75', '100', '1', '2');
    INSERT INTO "TEST_DATA_SOVLP" (ID, TD, IS_DB, TEST_SET) VALUES ('7', '80', '1', '2');
    
    2。用于存储结果的表

      CREATE TABLE "TEMP" 
       (    "DT" NUMBER, 
        "FLAG" VARCHAR2(1 BYTE)
       ) 
    
    CREATE OR REPLACE PROCEDURE S_OVLP 
    
    AS 
    
       CURSOR cSH IS
          SELECT ID, ESD, TD, IS_DB, TEST_SET
          FROM TEST_DATA_SOVLP
          WHERE TEST_SET = 2;
    
        rec_csh cSH%ROWTYPE;
    
    BEGIN
    
     -- DBMS_UTILITY.EXEC_DDL_STATEMENT('TRUNCATE TABLE TEMP');
    
      OPEN cSH;    
    
        LOOP
    
            FETCH cSH INTO rec_csh;
            EXIT WHEN cSH%NOTFOUND;
    
            IF rec_csh.esd IS NOT NULL THEN
                INSERT INTO TEMP VALUES (rec_csh.esd, 'E');
                dbms_output.put_line(rec_csh.esd || ' E');
            END IF;
    
            IF rec_csh.td IS NOT NULL THEN 
                IF rec_csh.is_db = 1 THEN     
                    INSERT INTO TEMP VALUES (rec_csh.td, 'H');
                    dbms_output.put_line(rec_csh.td || ' H');
                ELSE
                    INSERT INTO TEMP VALUES (rec_csh.td, 'S');
                    dbms_output.put_line(rec_csh.td || ' S');
                END IF;
            END IF;
    
        END LOOP;
    
      CLOSE cSH;
    
    END S_OVLP;
    
    3。PL/SQL操作数据并存储结果

      CREATE TABLE "TEMP" 
       (    "DT" NUMBER, 
        "FLAG" VARCHAR2(1 BYTE)
       ) 
    
    CREATE OR REPLACE PROCEDURE S_OVLP 
    
    AS 
    
       CURSOR cSH IS
          SELECT ID, ESD, TD, IS_DB, TEST_SET
          FROM TEST_DATA_SOVLP
          WHERE TEST_SET = 2;
    
        rec_csh cSH%ROWTYPE;
    
    BEGIN
    
     -- DBMS_UTILITY.EXEC_DDL_STATEMENT('TRUNCATE TABLE TEMP');
    
      OPEN cSH;    
    
        LOOP
    
            FETCH cSH INTO rec_csh;
            EXIT WHEN cSH%NOTFOUND;
    
            IF rec_csh.esd IS NOT NULL THEN
                INSERT INTO TEMP VALUES (rec_csh.esd, 'E');
                dbms_output.put_line(rec_csh.esd || ' E');
            END IF;
    
            IF rec_csh.td IS NOT NULL THEN 
                IF rec_csh.is_db = 1 THEN     
                    INSERT INTO TEMP VALUES (rec_csh.td, 'H');
                    dbms_output.put_line(rec_csh.td || ' H');
                ELSE
                    INSERT INTO TEMP VALUES (rec_csh.td, 'S');
                    dbms_output.put_line(rec_csh.td || ' S');
                END IF;
            END IF;
    
        END LOOP;
    
      CLOSE cSH;
    
    END S_OVLP;
    

    好的,我最终通过下面的代码得到了正确的结果,更改了嵌套的IF语句。 但是我对PL/SQL的工作方式非常失望

    CREATE OR REPLACE PROCEDURE S_OVLP 
    
    AS 
    
       CURSOR cSH IS
          SELECT ID, ESD, TD, IS_DB, TEST_SET
          FROM TEST_DATA_SOVLP
          WHERE TEST_SET = 2;
    
        rec_csh cSH%ROWTYPE;
    
    BEGIN
    
      DBMS_UTILITY.EXEC_DDL_STATEMENT('TRUNCATE TABLE TEMP');
    
      OPEN cSH;    
    
        LOOP
    
            FETCH cSH INTO rec_csh;
            EXIT WHEN cSH%NOTFOUND;
    
            IF rec_csh.esd IS NOT NULL THEN
                INSERT INTO TEMP VALUES (rec_csh.esd, 'E');
                dbms_output.put_line(rec_csh.esd || ' E');
            END IF;
    
            IF rec_csh.td IS NULL THEN 
                CONTINUE;
            END IF;
    
            IF rec_csh.is_db = 1 THEN     
                INSERT INTO TEMP VALUES (rec_csh.td, 'H');
                dbms_output.put_line(rec_csh.td || ' H');
            ELSE
                INSERT INTO TEMP VALUES (rec_csh.td, 'S');
                dbms_output.put_line(rec_csh.td || ' S');
            END IF;
    
        END LOOP;
    
      CLOSE cSH;
    
    END S_OVLP;
    

    好的,我最终通过下面的代码得到了正确的结果,更改了嵌套的IF语句。 但是我对PL/SQL的工作方式非常失望

    CREATE OR REPLACE PROCEDURE S_OVLP 
    
    AS 
    
       CURSOR cSH IS
          SELECT ID, ESD, TD, IS_DB, TEST_SET
          FROM TEST_DATA_SOVLP
          WHERE TEST_SET = 2;
    
        rec_csh cSH%ROWTYPE;
    
    BEGIN
    
      DBMS_UTILITY.EXEC_DDL_STATEMENT('TRUNCATE TABLE TEMP');
    
      OPEN cSH;    
    
        LOOP
    
            FETCH cSH INTO rec_csh;
            EXIT WHEN cSH%NOTFOUND;
    
            IF rec_csh.esd IS NOT NULL THEN
                INSERT INTO TEMP VALUES (rec_csh.esd, 'E');
                dbms_output.put_line(rec_csh.esd || ' E');
            END IF;
    
            IF rec_csh.td IS NULL THEN 
                CONTINUE;
            END IF;
    
            IF rec_csh.is_db = 1 THEN     
                INSERT INTO TEMP VALUES (rec_csh.td, 'H');
                dbms_output.put_line(rec_csh.td || ' H');
            ELSE
                INSERT INTO TEMP VALUES (rec_csh.td, 'S');
                dbms_output.put_line(rec_csh.td || ' S');
            END IF;
    
        END LOOP;
    
      CLOSE cSH;
    
    END S_OVLP;
    

    只需在中运行此
    插入,无需过程

    INSERT INTO temp 
    SELECT esd, 
           'E' 
    FROM   test_data_sovlp 
    WHERE  esd IS NOT NULL 
      UNION ALL 
    SELECT td, 
           CASE is_db 
             WHEN 0 THEN 'S' 
             WHEN 1 THEN 'H' 
           END AS FLAG 
    FROM   test_data_sovlp 
    WHERE  td IS NOT NULL 
    

    只需运行此
    插入到
    ,无需过程

    INSERT INTO temp 
    SELECT esd, 
           'E' 
    FROM   test_data_sovlp 
    WHERE  esd IS NOT NULL 
      UNION ALL 
    SELECT td, 
           CASE is_db 
             WHEN 0 THEN 'S' 
             WHEN 1 THEN 'H' 
           END AS FLAG 
    FROM   test_data_sovlp 
    WHERE  td IS NOT NULL 
    

    从您的业务规则来看,似乎只需插入两个插件即可完成,如下所示:

    insert into temp
    select esd, 'E' from TEST_DATA_SOVLP where test_set=2 and esd is not null;
    
    insert into temp
    select td, decode(is_db, 1, 'H', 'S') from TEST_DATA_SOVLP 
         where test_set=2 and td is not null;
    
    除了在
    esd
    td
    上的条件外,还选择了在
    test\u set
    上“嵌入”条件,该条件由过程中的光标给出

    INSERT INTO temp 
    SELECT esd, 
           'E' 
    FROM   test_data_sovlp 
    WHERE  esd IS NOT NULL 
      UNION ALL 
    SELECT td, 
           CASE is_db 
             WHEN 0 THEN 'S' 
             WHEN 1 THEN 'H' 
           END AS FLAG 
    FROM   test_data_sovlp 
    WHERE  td IS NOT NULL 
    
    decode
    is_db
    与1进行比较,如果匹配,则使用
    'H'
    ,否则使用
    'S'
    (因此2将给出与0相同的结果;但我认为您需要检查数据,因为您已经定义了仅为1或0提供的内容)

    关于程序 我已经对其进行了测试,输出看起来很好:

    10 E
    20 H
    30 E
    40 E
    50 E
    60 H
    70 H
    75 E
    100 H
    80 H
    
    (表中的所有
    都是_db=1
    ,请参见您在问题中给出的插入)


    此外,相应地填充
    temp
    表。因此,这个问题无法复制,而且您的原始过程似乎按照预期运行良好。

    从您的业务规则来看,似乎只需插入两个插件即可完成,如下所示:

    insert into temp
    select esd, 'E' from TEST_DATA_SOVLP where test_set=2 and esd is not null;
    
    insert into temp
    select td, decode(is_db, 1, 'H', 'S') from TEST_DATA_SOVLP 
         where test_set=2 and td is not null;
    
    除了在
    esd
    td
    上的条件外,还选择了在
    test\u set
    上“嵌入”条件,该条件由过程中的光标给出

    INSERT INTO temp 
    SELECT esd, 
           'E' 
    FROM   test_data_sovlp 
    WHERE  esd IS NOT NULL 
      UNION ALL 
    SELECT td, 
           CASE is_db 
             WHEN 0 THEN 'S' 
             WHEN 1 THEN 'H' 
           END AS FLAG 
    FROM   test_data_sovlp 
    WHERE  td IS NOT NULL 
    
    decode
    is_db
    与1进行比较,如果匹配,则使用
    'H'
    ,否则使用
    'S'
    (因此2将给出与0相同的结果;但我认为您需要检查数据,因为您已经定义了仅为1或0提供的内容)

    关于程序 我已经对其进行了测试,输出看起来很好:

    10 E
    20 H
    30 E
    40 E
    50 E
    60 H
    70 H
    75 E
    100 H
    80 H
    
    (表中的所有
    都是_db=1
    ,请参见您在问题中给出的插入)


    此外,相应地填充
    temp
    表。因此,问题无法复制,您的原始过程似乎与预期一样正常。

    应该完全相同。Oracle的哪个版本?可能是因为你错过了一次提交而什么也没看到吗?太多的
    if
    条件和循环。不要使用此代码。编辑您的问题并解释获取
    temp
    表记录所需的条件。切勿为样本数据添加图像,仅使用纯文本。可以编写一个
    插入select*
    查询来实现这一点,这比循环和条件要有效得多。最后,不要因为编写代码的糟糕方式而责怪PL/SQL。似乎您还没有使用该语言最强大的功能。@KaushikNayak我认为即使没有pl也可以做到,只有两个(使用decode…)插入语句并从“源”表中进行适当选择…@ShinTakezou:您从哪里读到我说我希望使用pl/SQL完成此任务的?@KaushikNayak Nowhere,我只是对这段代码所带来的奇怪之处添加了一条评论——这是写给你的,因为你提醒了OP pl/sql有多强大,所以我在最后一句话之后补充说,在这种情况下,我认为他(OP)甚至不需要这种能力。应该是完全一样的。Oracle的哪个版本?可能是因为你错过了一次提交而什么也没看到吗?太多的
    if
    条件和循环。不要使用此代码。编辑您的问题并解释获取
    temp
    表记录所需的条件。切勿为样本数据添加图像,仅使用纯文本。可以编写一个
    插入select*
    查询来实现这一点,这比循环和条件要有效得多。最后,不要因为编写代码的糟糕方式而责怪PL/SQL。似乎您还没有使用该语言最强大的功能。@KaushikNayak我认为即使没有pl也可以做到,只有两个(使用decode…)插入语句并从“源”表中进行适当选择…@ShinTakezou:您从哪里读到我说我希望使用pl/SQL完成此任务的?@KaushikNayak Nowhere,我只是对这段代码所带来的奇怪之处添加了一条评论——这是写给你的,因为你提醒了OP pl/sql有多强大,所以我按照上一句话补充说,在这种情况下,我认为他(OP)甚至不需要这种能力。这看起来不错。上vo