Oracle
 sql >> база данни >  >> RDS >> Oracle

Курсор на Oracle за присвояване

Настройте типовете данни и помощните функции:

CREATE TYPE string_list IS TABLE OF VARCHAR2(2);
/

CREATE TYPE int_list IS TABLE OF INT;
/

CREATE TYPE t1_data AS OBJECT(
  vk VARCHAR2(4),
  ay VARCHAR2(2),
  an VARCHAR2(14),
  r  INT,
  c  VARCHAR2(2)
);
/

CREATE TYPE t1_table IS TABLE OF t1_data;
/

CREATE OR REPLACE FUNCTION split_String(
  i_str    IN  VARCHAR2,
  i_delim  IN  VARCHAR2 DEFAULT ','
) RETURN string_list DETERMINISTIC
AS
  p_result       string_list := string_list();
  p_start        NUMBER(5) := 1;
  p_end          NUMBER(5);
  c_len CONSTANT NUMBER(5) := LENGTH( i_str );
  c_ld  CONSTANT NUMBER(5) := LENGTH( i_delim );
BEGIN
  -- https://stackoverflow.com/a/35577315/1509264
  -- License: CC BY-SA 4.0
  IF c_len > 0 THEN
    p_end := INSTR( i_str, i_delim, p_start );
    WHILE p_end > 0 LOOP
      p_result.EXTEND;
      p_result( p_result.COUNT ) := SUBSTR( i_str, p_start, p_end - p_start );
      p_start := p_end + c_ld;
      p_end := INSTR( i_str, i_delim, p_start );
    END LOOP;
    IF p_start <= c_len + 1 THEN
      p_result.EXTEND;
      p_result( p_result.COUNT ) := SUBSTR( i_str, p_start, c_len - p_start + 1 );
    END IF;
  END IF;
  RETURN p_result;
END;
/

След това можете да използвате функцията:

CREATE FUNCTION pick_values RETURN t1_table PIPELINED
IS
  TYPE t2_type IS TABLE OF t2%ROWTYPE;
  
  t2_data t2_type;
BEGIN
  -- https://stackoverflow.com/a/67398434/1509264
  -- License: CC BY-SA 4.0
  SELECT *
  BULK COLLECT INTO t2_data
  FROM  t2;
  
  FOR cur IN ( SELECT * FROM t1 ORDER BY r )
  LOOP
    DECLARE
      a_freqs  INT_LIST := INT_LIST();
      cum_freq INT := 0;
      taken    STRING_LIST := SPLIT_STRING( cur.an, ', ' );
      idx      INT;
      c        T2.A%TYPE;
    BEGIN
      a_freqs.EXTEND(t2_data.COUNT);
      FOR i IN 1 .. t2_data.COUNT LOOP
        IF ( t2_data(i).a = cur.ay AND t2_data(i).c > 0 )
           OR ( cur.ay IS NULL AND t2_data(i).a NOT MEMBER OF taken AND t2_data(i).c > 0 )
        THEN
          a_freqs(i) := cum_freq + t2_data(i).c;
          cum_freq := cum_freq + t2_data(i).c;
        ELSE
          a_freqs(i) := cum_freq;
        END IF;
      END LOOP;
      IF cum_freq > 0 THEN
        idx := FLOOR(DBMS_RANDOM.VALUE(0, cum_freq));
        FOR i IN 1 .. t2_data.COUNT LOOP
          IF idx < a_freqs(i) THEN
            c := t2_data(i).a;
            t2_data(i).c := t2_data(i).c - 1;
            EXIT;
          END IF;
        END LOOP;
      END IF;
      PIPE ROW(
        t1_data(
          cur.vk, cur.ay, cur.an, cur.r, c
        )
      );
    END;
  END LOOP;
END;
/

Което за примерните ви данни:

CREATE TABLE t1 (vk, ay, an, r) as
    select 'VK1', null, 'A1, A2', 1 from dual union all
    select 'VK2', null, null, 2 from dual union all
    select 'VK3', null, 'A1, A2, A3, A4', 3 from dual union all
    select 'VK4', null, 'A2', 4 from dual union all
    select 'VK5', null, null, 5 from dual union all
    select 'VK6', null, null, 6 from dual union all
    select 'VK7', 'A3', null, 7 from dual union all
    select 'VK8', null, null, 8 from dual union all
    select 'VK9', null, null, 9 from dual union all
    select 'VK10', null, null, 10 from dual union all
    select 'VK11', null, null, 11 from dual union all
    select 'VK12', null, null, 12 from dual union all
    select 'VK13', 'A3', null, 13 from dual union all
    select 'VK14', null, null, 14 from dual union all
    select 'VK15', 'A3', null, 15 from dual union all
    select 'VK16', null, null, 16 from dual union all
    select 'VK17', null, null, 17 from dual union all
    select 'VK18', null, null, 18 from dual union all
    select 'VK19', null, null, 19 from dual union all
    select 'VK20', null, null, 20 from dual;

CREATE TABLE t2 (a, c) as
    select 'A1', 4 from dual union all
    select 'A2', 10 from dual union all
    select 'A3', 2 from dual union all
    select 'A4', 10 from dual;

След това:

SELECT * FROM PICK_VALUES();

Може да изведе:

VK ДА AN R C VK1A1, A21A4VK22A2VK3A1, A2, A3, A43VK4A24A1VK55A2VK66A2VK7A37A3VK88A1VK99A2VK1010A4VK1111A2VK1212A1VK13A313A3VK1414A4VK15A315VK1616A4VK1717A2VK1818A4VK1919A4VK2020A4

db<>цигулка тук




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. как да намерите индекси на таблица в oracle

  2. Парсер за Oracle SQL

  3. Проблем с преобразуване на Oracle SQL DATE при използване на iBATIS чрез Java JDBC

  4. Към какво съпоставя Hibernate булев тип данни, когато се използва база данни на Oracle по подразбиране?

  5. PreparedStatement въпрос в Java срещу Oracle