Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在一组行之后或在没有PL/SQL块的情况下有条件地递增oracle序列?_Sql_Database_Oracle_Plsql_Oracle11g - Fatal编程技术网

如何在一组行之后或在没有PL/SQL块的情况下有条件地递增oracle序列?

如何在一组行之后或在没有PL/SQL块的情况下有条件地递增oracle序列?,sql,database,oracle,plsql,oracle11g,Sql,Database,Oracle,Plsql,Oracle11g,我正在尝试执行代码重写。其中之一就是这个怪物。我有一组普通的DML,突然在脚本中出现了这个PL/SQL块(请参阅当前的解决方案),这在SQL DML中看起来很奇怪 最初,我们决定使用PL/SQL块,其假设是,“在记录组中使用序列号更新列而不使用增量,在下一组中使用增量是无法在单个SQL中实现的。” 问题:如何在一组行之后或有条件地递增oracle序列 数据设置: CREATE TABLE TEMP_GP_SEQ ( COL1 NUMBER, COL2 NUMBER, C

我正在尝试执行代码重写。其中之一就是这个怪物。我有一组普通的DML,突然在脚本中出现了这个PL/SQL块(请参阅当前的解决方案),这在SQL DML中看起来很奇怪

最初,我们决定使用PL/SQL块,其假设是,
“在记录组中使用序列号更新列而不使用增量,在下一组中使用增量是无法在单个SQL中实现的。”

问题:如何在一组行之后或有条件地递增oracle序列

数据设置:

CREATE TABLE TEMP_GP_SEQ
(
   COL1   NUMBER,
   COL2   NUMBER,
   COL3   NUMBER,
   COL4   NUMBER,
   COL5   NUMBER,
   COL6   NUMBER,
   COL7   VARCHAR2 (10)
);

INSERT INTO TEMP_GP_SEQ VALUES(1,10,100,NULL,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(1,10,101,NULL,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(12,10,100,1,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(1,10,100,2,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(1,10,100,3,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(12,10,100,1,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(2,10,100,NULL,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(2,10,101,NULL,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(2,10,101,1,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(2,10,101,1,NULL,NULL,NULL);

COMMIT; 

CREATE SEQUENCE SEQ_TEMP_TEST
   START WITH 1
   INCREMENT BY 1;
DECLARE
    VAL INTEGER;
BEGIN
    FOR REC IN ( SELECT
                    COL1,
                    COL3,
                    COL4
              FROM
                    TEMP_GP_SEQ
              GROUP BY
                    COL1,
                    COL3,
                    COL4
              HAVING
                    COUNT ( * ) > 1 )
    LOOP
        SELECT SEQ_TEMP_TEST.NEXTVAL INTO VAL FROM DUAL;

        UPDATE
              TEMP_GP_SEQ
        SET
              COL7   = 'M' || VAL
        WHERE
                 ( COL1 = REC.COL1 OR ( COL1 IS NULL AND REC.COL1 IS NULL ) )
              AND ( COL3 = REC.COL3 OR ( COL3 IS NULL AND REC.COL3 IS NULL ) )
              AND ( COL4 = REC.COL4 OR ( COL4 IS NULL AND REC.COL4 IS NULL ) );
    END LOOP;
END;
/
SELECT
      A.COL1,
      A.COL2,
      A.COL3,
      A.COL4,
      A.COL5,
      A.COL6,
      DECODE ( B.ID, NULL, '', 'M' )
      || SEQ
          AS COL7
FROM
      TEMP_GP_SEQ A,
      (SELECT
            COL1,
            COL3,
            COL4,
            RETSEQ SEQ,
            ROW_NUMBER ( )
                OVER ( ORDER BY
                          COL1,
                          COL3,
                          COL4 )
                ID
       FROM
            TEMP_GP_SEQ
       GROUP BY
            COL1,
            COL3,
            COL4
       HAVING
            COUNT ( * ) > 1) B
WHERE
         A.COL1 = B.COL1(+)
      AND A.COL3 = B.COL3(+)
      AND A.COL4 = B.COL4(+);
因此,我的相关记录的选择标准

SELECT
      COL1,
      COL3,
      COL4,
      COUNT ( * )
FROM
      TEMP_GP_SEQ
GROUP BY
      COL1,
      COL3,
      COL4
HAVING
      COUNT ( * ) > 1;
会给我

COL1    COL3    COL4    COUNT(*)
2       101     1       2
12      100     1       2
我需要根据上面提到的分组范围,使用创建的序列更新临时表和COL7列上的临时表。但是序列不应该为每个记录递增,它应该只为组的更改递增。比如说

SELECT 
      COL1,
      COL2,
      COL3,
      COL4,
      COL7
FROM
      TEMP_GP_SEQ;
所需输出

COL1    COL2    COL3   COL4    COL7         
1       10      100    NULL    NULL         
1       10      101    NULL    NULL         
12      10      100    1       M2           
1       10      100    2       NULL         
1       10      100    3       NULL         
12      10      100    1       M2           
2       10      100    NULL    NULL         
2       10      101    NULL    NULL         
2       10      101    1       M1           
2       10      101    1       M1           
COL7在这四行中更新,前缀为M,M后的数字来自序列。在这里,只有当分组标准发生变化并且在整个组中保持不变时,数字才会发生变化(序列递增)

挑战在于任何列中都可能存在空值。因此,在分组时,应考虑空值。因此使用的是NULL。(为了确保安全,NVL被忽略)

现有解决方案:

CREATE TABLE TEMP_GP_SEQ
(
   COL1   NUMBER,
   COL2   NUMBER,
   COL3   NUMBER,
   COL4   NUMBER,
   COL5   NUMBER,
   COL6   NUMBER,
   COL7   VARCHAR2 (10)
);

INSERT INTO TEMP_GP_SEQ VALUES(1,10,100,NULL,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(1,10,101,NULL,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(12,10,100,1,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(1,10,100,2,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(1,10,100,3,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(12,10,100,1,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(2,10,100,NULL,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(2,10,101,NULL,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(2,10,101,1,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(2,10,101,1,NULL,NULL,NULL);

COMMIT; 

CREATE SEQUENCE SEQ_TEMP_TEST
   START WITH 1
   INCREMENT BY 1;
DECLARE
    VAL INTEGER;
BEGIN
    FOR REC IN ( SELECT
                    COL1,
                    COL3,
                    COL4
              FROM
                    TEMP_GP_SEQ
              GROUP BY
                    COL1,
                    COL3,
                    COL4
              HAVING
                    COUNT ( * ) > 1 )
    LOOP
        SELECT SEQ_TEMP_TEST.NEXTVAL INTO VAL FROM DUAL;

        UPDATE
              TEMP_GP_SEQ
        SET
              COL7   = 'M' || VAL
        WHERE
                 ( COL1 = REC.COL1 OR ( COL1 IS NULL AND REC.COL1 IS NULL ) )
              AND ( COL3 = REC.COL3 OR ( COL3 IS NULL AND REC.COL3 IS NULL ) )
              AND ( COL4 = REC.COL4 OR ( COL4 IS NULL AND REC.COL4 IS NULL ) );
    END LOOP;
END;
/
SELECT
      A.COL1,
      A.COL2,
      A.COL3,
      A.COL4,
      A.COL5,
      A.COL6,
      DECODE ( B.ID, NULL, '', 'M' )
      || SEQ
          AS COL7
FROM
      TEMP_GP_SEQ A,
      (SELECT
            COL1,
            COL3,
            COL4,
            RETSEQ SEQ,
            ROW_NUMBER ( )
                OVER ( ORDER BY
                          COL1,
                          COL3,
                          COL4 )
                ID
       FROM
            TEMP_GP_SEQ
       GROUP BY
            COL1,
            COL3,
            COL4
       HAVING
            COUNT ( * ) > 1) B
WHERE
         A.COL1 = B.COL1(+)
      AND A.COL3 = B.COL3(+)
      AND A.COL4 = B.COL4(+);
真的有可能将其重构为普通SQL而不是PL/SQL块吗? 如果您需要任何澄清,请告诉我


任何想尝试的人都可以看到小提琴

如果我正确理解您的问题,此查询将满足您的要求,那么您只需要使用它来更新您的行但是我没有使用
更新
来更改行,也没有使用fiddle,因为(我不知道为什么)它不允许我创建函数

为了运行select语句,我需要创建一个函数来返回序列,因为oracle不允许我在sql语句中使用它(至少在我的10.2.x版本中不允许)

首先,我创建了这个函数:

create or replace function retSeq return number
as
   n number;
begin
   select SEQ_TEMP_TEST.nextval into n from dual;
   return n;
end;
然后我做了select语句。我认为把代码改成这个会使它更难理解。但问题是要用一个查询解决问题,我几乎做到了(必须创建函数)。所以,不要害怕:

SELECT s1.col1, s1.col2, s1.col3, s1.col4, s1.col5, s1.col6, 
       decode(s1.id,null,'','M')
           || (SELECT retseq seq
                 FROM (SELECT   col1, col3, col4,
                                ROW_NUMBER () OVER (ORDER BY col1, col3, col4) ID
                         FROM temp_gp_seq
                        GROUP BY col1, col3, col4
                       HAVING COUNT (*) > 1)
                WHERE ID = s1.ID)
           as col7 
  FROM (SELECT a.*, b.ID
          FROM temp_gp_seq a,
               (SELECT col1, col3, col4,
                       ROW_NUMBER () OVER (ORDER BY col1, col3, col4) ID
                  FROM (SELECT   col1, col3, col4, COUNT (*) ct
                            FROM temp_gp_seq
                        GROUP BY col1, col3, col4
                          HAVING COUNT (*) > 1)) b
         WHERE a.col1 = b.col1(+) 
           AND a.col3 = b.col3(+)
           AND a.col4 = b.col4(+)) s1
结果将是(在第一次运行时,由于顺序原因)

由OP跟进:

CREATE TABLE TEMP_GP_SEQ
(
   COL1   NUMBER,
   COL2   NUMBER,
   COL3   NUMBER,
   COL4   NUMBER,
   COL5   NUMBER,
   COL6   NUMBER,
   COL7   VARCHAR2 (10)
);

INSERT INTO TEMP_GP_SEQ VALUES(1,10,100,NULL,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(1,10,101,NULL,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(12,10,100,1,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(1,10,100,2,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(1,10,100,3,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(12,10,100,1,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(2,10,100,NULL,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(2,10,101,NULL,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(2,10,101,1,NULL,NULL,NULL);
INSERT INTO TEMP_GP_SEQ VALUES(2,10,101,1,NULL,NULL,NULL);

COMMIT; 

CREATE SEQUENCE SEQ_TEMP_TEST
   START WITH 1
   INCREMENT BY 1;
DECLARE
    VAL INTEGER;
BEGIN
    FOR REC IN ( SELECT
                    COL1,
                    COL3,
                    COL4
              FROM
                    TEMP_GP_SEQ
              GROUP BY
                    COL1,
                    COL3,
                    COL4
              HAVING
                    COUNT ( * ) > 1 )
    LOOP
        SELECT SEQ_TEMP_TEST.NEXTVAL INTO VAL FROM DUAL;

        UPDATE
              TEMP_GP_SEQ
        SET
              COL7   = 'M' || VAL
        WHERE
                 ( COL1 = REC.COL1 OR ( COL1 IS NULL AND REC.COL1 IS NULL ) )
              AND ( COL3 = REC.COL3 OR ( COL3 IS NULL AND REC.COL3 IS NULL ) )
              AND ( COL4 = REC.COL4 OR ( COL4 IS NULL AND REC.COL4 IS NULL ) );
    END LOOP;
END;
/
SELECT
      A.COL1,
      A.COL2,
      A.COL3,
      A.COL4,
      A.COL5,
      A.COL6,
      DECODE ( B.ID, NULL, '', 'M' )
      || SEQ
          AS COL7
FROM
      TEMP_GP_SEQ A,
      (SELECT
            COL1,
            COL3,
            COL4,
            RETSEQ SEQ,
            ROW_NUMBER ( )
                OVER ( ORDER BY
                          COL1,
                          COL3,
                          COL4 )
                ID
       FROM
            TEMP_GP_SEQ
       GROUP BY
            COL1,
            COL3,
            COL4
       HAVING
            COUNT ( * ) > 1) B
WHERE
         A.COL1 = B.COL1(+)
      AND A.COL3 = B.COL3(+)
      AND A.COL4 = B.COL4(+);

PS:删除了不必要的子查询,并将窗口函数组合在一个查询中。

我相信任何pl/sql都可以转换为sql。我经常使用NVL来避免空值,也许这会有所帮助?我也相信这一点,因此发布了以下内容:)。只有当我
1000%确定虚拟值永远不会出现在列上时,才能使用
NVL
。为了避免这种情况,我使用了
IS NULL
。ROWNUM在oracle中也是一个有用的转换结构。仍然在看你的SQL代码,我的眼睛都睁大了。这个序列是必要的吗?或者你可以考虑不使用它?绝对必要。这正是我所做的,我检查并简化了你的查询,但逻辑上完全正确。:)见下文up@realspirituals是的,那太好了,我是一步一步地解决问题的,我没有尽可能地去做。感谢您的跟进:)