PL/sqloracle。实现包含IS_运算符的最佳方法

PL/sqloracle。实现包含IS_运算符的最佳方法,oracle,plsql,intersect,multiset,regexp-substr,Oracle,Plsql,Intersect,Multiset,Regexp Substr,我是新手,所以这个问题可能已经被问过一两万次了,但它在知识数据库中是不可查找/搜索的 在Oracle PL/SQL中,通常会进行如下查询: select a,b,c from table_foo where c in (select k from table(array_bar)); 但我需要的恰恰相反。我需要一种包含运算符,如下所示: select a,b,c from table_foo where AT_LEAST_ONE_OF_THE_ITEMS_IN (selec

我是新手,所以这个问题可能已经被问过一两万次了,但它在知识数据库中是不可查找/搜索的

在Oracle PL/SQL中,通常会进行如下查询:

select a,b,c 
from   table_foo 
where  c in (select k from table(array_bar));
但我需要的恰恰相反。我需要一种包含运算符,如下所示:

select a,b,c 
from   table_foo 
where  AT_LEAST_ONE_OF_THE_ITEMS_IN (select k from table(array_bar)) IS_CONTAINED_IN c;
CODE    DESCRIPTION   CITIES_LIST
----    -----------   -----------
0001    Desc 0001     London; Berlin; NY; SF
0002    Desc 0002     Paris; Madrid; Rome
0003    Desc 0003     Berlin; Paris; London
0004    Desc 0004     Madrid;NY;Tokyo
0005    Repe 0005     Rome;Rome;Rome;LA;LA;LA;
0006    One  0006     NY
0007    Desc 0007     Sydney;Tokyo;Madrid
0008    Desc 0008     LA;SF;NY
0009    Desc 0009     Seoul;Beijing;
0010    Error0010     Beijing;;;;OZ;
0011    None 0011     (null)
0012    All  0012     London;Paris;Berlin;Madrid;Rome;NY;SF;LA;Seoul;Beijing;Tokyo;Sydney
我有自己的想法,使用带循环的函数来实现它。但是也许一些天才已经找到了一种简单的方法,不用函数就可以实现。也就是说,可能操作符是Oracle发明的,我还没有发现

对不起,如果这个问题重复。我保证我已经在知识库中搜索过了。但是,在这个宇宙的时空中,似乎没有人从来都不需要超明显的算符

解决方案:

谢谢大家的建议。最后,我不得不使用一些函数,但我认为我得到了一个很好的解决方案。情况是:我有一个中心表。每个中心可以位于一个或多个城市,也就是说,这是一个1对N的关系。但这种关系是使用一个表完成的。此表包含一些字段。其中一个名为“cities_list”的字段包含所有用分号分隔的相关城市。是这样的:

select a,b,c 
from   table_foo 
where  AT_LEAST_ONE_OF_THE_ITEMS_IN (select k from table(array_bar)) IS_CONTAINED_IN c;
CODE    DESCRIPTION   CITIES_LIST
----    -----------   -----------
0001    Desc 0001     London; Berlin; NY; SF
0002    Desc 0002     Paris; Madrid; Rome
0003    Desc 0003     Berlin; Paris; London
0004    Desc 0004     Madrid;NY;Tokyo
0005    Repe 0005     Rome;Rome;Rome;LA;LA;LA;
0006    One  0006     NY
0007    Desc 0007     Sydney;Tokyo;Madrid
0008    Desc 0008     LA;SF;NY
0009    Desc 0009     Seoul;Beijing;
0010    Error0010     Beijing;;;;OZ;
0011    None 0011     (null)
0012    All  0012     London;Paris;Berlin;Madrid;Rome;NY;SF;LA;Seoul;Beijing;Tokyo;Sydney
可能的城市有:伦敦;巴黎柏林马德里罗马纽约;SF;洛杉矶;首尔北京,;东京悉尼

为了过滤该表的记录,用户可以通过组合选择一个或多个城市。选定的城市作为城市的字符串varchar传递给PL/SQL查询,这些城市由散列符号分隔。例如“伦敦巴黎悉尼”

PL/SQL必须选择字段“cities\u list”和从组合中传递的城市字符串之间至少有一个公共城市的记录。首先,我将PL/SQL代码放在这里,稍后我将对其进行解释:

--1.SELECT AND EXECUTE THIS:
    SET SERVEROUTPUT ON;

--2.SELECT AND EXECUTE THIS:
    DROP TABLE table_centers; CREATE GLOBAL TEMPORARY TABLE table_centers (code VARCHAR2(10), description VARCHAR2(100), cities_list VARCHAR2(1000));

--3.SELECT AND EXECUTE THIS:
    CREATE OR REPLACE TYPE table_TYPE IS TABLE OF VARCHAR2(250);

--4.SELECT AND EXECUTE THIS:
    CREATE OR REPLACE FUNCTION VARCHAR_TO_TABLE (input_varchar VARCHAR2, separator VARCHAR2 DEFAULT ';')
    RETURN table_TYPE
        IS
            --VARS
            output_table table_TYPE := table_TYPE(); 
        BEGIN
            --For better performance, input_varchar is splitted without blanks into output_table using the regular expression [^;]+
            SELECT
                --The Keyword 'level' in statement 'regexp_substr' refers to a pseudocolumn in Oracle
                TRIM(regexp_substr(input_varchar,'[^' || separator || ']+', 1, level))
            BULK COLLECT INTO
                output_table
            FROM DUAL
            CONNECT BY
                regexp_substr(input_varchar,'[^' || separator || ']+', 1, level) IS NOT NULL;
            --Now we have all chunks into the table output_table
        RETURN output_table;
    END VARCHAR_TO_TABLE;

--5.SELECT AND EXECUTE THIS:
    CREATE OR REPLACE FUNCTION INTERSECT_TABLES(input_A VARCHAR2 , separator_A VARCHAR2 , input_B VARCHAR2 , separator_B VARCHAR2)
    RETURN NUMBER
        IS
            --VARS
            A table_TYPE;
            B table_TYPE;
            result BOOLEAN;
        BEGIN
            --Splits input_A and input_B into tables and checks if there is overlapping
            A := VARCHAR_TO_TABLE(input_A, separator_A);
            B := VARCHAR_TO_TABLE(input_B, separator_B);
            --If intersection is not empty result is TRUE
            result := A multiset intersect B is not empty;        
            -- Returns 1 if intersection is not empty, returns 0 otherwise (Note that functions called from a SQL query cannot take any BOOLEAN parameters)
            IF result = TRUE THEN RETURN 1; ELSE RETURN 0; END IF;
    END INTERSECT_TABLES;

--6.SELECT AND EXECUTE THIS:
    CREATE OR REPLACE PROCEDURE GET_CENTERS (cities_input VARCHAR2 , separator_input VARCHAR2 , out_Cursor OUT sys_refcursor)
    AS
    BEGIN       
        OPEN out_Cursor FOR
        SELECT tc.code, tc.description, tc.cities_list
        FROM   table_centers tc
        --Has current record some city in common with cities_input? If yes, select current record
        WHERE  INTERSECT_TABLES(cities_input , separator_input , tc.cities_list , ';') = 1;
    END GET_CENTERS;

--7.SELECT AND EXECUTE THIS:
    BEGIN
        DELETE FROM table_centers; COMMIT;
        INSERT ALL
            --We'll use following cities: London Paris Berlin Madrid Rome NY SF LA Seoul Beijing Tokyo Sydney
            INTO table_centers (code,description,cities_list) VALUES ('0001', 'Desc 0001', 'London; Berlin; NY; SF')
            INTO table_centers (code,description,cities_list) VALUES ('0002', 'Desc 0002', 'Paris; Madrid; Rome')
            INTO table_centers (code,description,cities_list) VALUES ('0003', 'Desc 0003', 'Berlin; Paris; London')
            INTO table_centers (code,description,cities_list) VALUES ('0004', 'Desc 0004', 'Madrid;NY;Tokyo')
            INTO table_centers (code,description,cities_list) VALUES ('0005', 'Repe 0005', 'Rome;Rome;Rome;LA;LA;LA;')
            INTO table_centers (code,description,cities_list) VALUES ('0006', 'One  0006', 'NY')
            INTO table_centers (code,description,cities_list) VALUES ('0007', 'Desc 0007', 'Sydney;Tokyo;Madrid')
            INTO table_centers (code,description,cities_list) VALUES ('0008', 'Desc 0008', 'LA;SF;NY')
            INTO table_centers (code,description,cities_list) VALUES ('0009', 'Desc 0009', 'Seoul;Beijing;')
            INTO table_centers (code,description,cities_list) VALUES ('0010', 'Error0010', 'Beijing;;;;OZ;')
            INTO table_centers (code,description,cities_list) VALUES ('0011', 'None 0011', '')
            INTO table_centers (code,description,cities_list) VALUES ('0012', 'All  0012', 'London;Paris;Berlin;Madrid;Rome;NY;SF;LA;Seoul;Beijing;Tokyo;Sydney')
        SELECT 1 FROM DUAL;
    END;

--8.SELECT AND EXECUTE THIS:
    SELECT * FROM table_centers;
我使用了“Oracle SQL开发人员”。您可以逐个选择句子,并使用F9键执行它们。您还可以创建一个包

如果有人想要测试该代码,您还可以选择并使用F9执行以下查询:

--9.SELECT AND EXECUTE THIS:
    DECLARE
        --VARS
        out_Cursor      sys_refcursor;
        cities_array    table_TYPE;
        citiesA         varchar(1000) := 'London#Paris#Berlin#Madrid#Rome#NY#SF#LA# Seoul # Beijing # Tokyo # Sydney ';
        citiesB         varchar(1000) := 'London;Paris;Berlin;Madrid;Rome;NY;SF;LA; Seoul ; Beijing ; Tokyo ; Sydney ';
        Rcode           table_centers.code%TYPE;
        Rdescription    table_centers.description%TYPE;
        Rcities_list    table_centers.cities_list%TYPE;
        CR              char := CHR(13);
        TAB             char := CHR(9);
    BEGIN
        --TEST 1
            dbms_output.put_line('TEST 1: ' || CR);
            cities_array := table_TYPE();
            cities_array := VARCHAR_TO_TABLE(citiesA, '#');
            --Now we have all cities in the array cities_array
            FOR elem in 1 .. cities_array.count LOOP
                dbms_output.put_line(TAB || elem || ':' || cities_array(elem) || '.');
            END LOOP;
        --TEST 2
            dbms_output.put_line('TEST 2: ' || CR);
            cities_array := table_TYPE();
            cities_array := VARCHAR_TO_TABLE(citiesB, ';');
            --Now we have all cities in the array cities_array
            FOR elem in 1 .. cities_array.count LOOP
                dbms_output.put_line(TAB || elem || ':' || cities_array(elem) || '.');
            END LOOP;
        --TEST 3
            dbms_output.put_line('TEST 3: ' || CR);
            GET_CENTERS(citiesA, '#', out_Cursor);
            fetch out_Cursor into Rcode,Rdescription,Rcities_list;
            WHILE out_Cursor%FOUND LOOP
                dbms_output.put_line(TAB || 'CITIES:' || Rcities_list || '.');
                fetch out_Cursor into Rcode,Rdescription,Rcities_list;
            END LOOP;
            close out_Cursor;
        --TEST 4
            dbms_output.put_line('TEST 4: ' || CR);
            GET_CENTERS('London#Paris#Sydney', '#', out_Cursor);
            fetch out_Cursor into Rcode,Rdescription,Rcities_list;
            WHILE out_Cursor%FOUND LOOP
                dbms_output.put_line(TAB || 'CITIES:' || Rcities_list || '.');
                fetch out_Cursor into Rcode,Rdescription,Rcities_list;
            END LOOP;
            close out_Cursor;
        --TEST 5
            dbms_output.put_line('TEST 5: ' || CR);
            GET_CENTERS('Madrid', '#', out_Cursor);
            fetch out_Cursor into Rcode,Rdescription,Rcities_list;
            WHILE out_Cursor%FOUND LOOP
                dbms_output.put_line(TAB || 'CITIES:' || Rcities_list || '.');
                fetch out_Cursor into Rcode,Rdescription,Rcities_list;
            END LOOP;
            close out_Cursor;
        --TEST 6
            dbms_output.put_line('TEST 6: ' || CR);
            GET_CENTERS('Gotham City', '#', out_Cursor);
            fetch out_Cursor into Rcode,Rdescription,Rcities_list;
            WHILE out_Cursor%FOUND LOOP
                dbms_output.put_line(TAB || 'CITIES:' || Rcities_list || '.');
                fetch out_Cursor into Rcode,Rdescription,Rcities_list;
            END LOOP;
            close out_Cursor;
        --TEST 7
            dbms_output.put_line('TEST 7: ' || CR);
            GET_CENTERS('', '#', out_Cursor);
            fetch out_Cursor into Rcode,Rdescription,Rcities_list;
            WHILE out_Cursor%FOUND LOOP
                dbms_output.put_line(TAB || 'CITIES:' || Rcities_list || '.');
                fetch out_Cursor into Rcode,Rdescription,Rcities_list;
            END LOOP;
            close out_Cursor;
    END;
您可以修改测试7,并将自己的值放入函数“GET_CENTERS”的第一个参数中。我已执行此查询,并得到以下结果:

TEST 1: 
    1:London.
    2:Paris.
    3:Berlin.
    4:Madrid.
    5:Rome.
    6:NY.
    7:SF.
    8:LA.
    9:Seoul.
    10:Beijing.
    11:Tokyo.
    12:Sydney.
TEST 2: 
    1:London.
    2:Paris.
    3:Berlin.
    4:Madrid.
    5:Rome.
    6:NY.
    7:SF.
    8:LA.
    9:Seoul.
    10:Beijing.
    11:Tokyo.
    12:Sydney.
TEST 3: 
    CITIES:London; Berlin; NY; SF.
    CITIES:Paris; Madrid; Rome.
    CITIES:Berlin; Paris; London.
    CITIES:Madrid;NY;Tokyo.
    CITIES:Rome;Rome;Rome;LA;LA;LA;.
    CITIES:NY.
    CITIES:Sydney;Tokyo;Madrid.
    CITIES:LA;SF;NY.
    CITIES:Seoul;Beijing;.
    CITIES:Beijing;;;;OZ;.
    CITIES:London;Paris;Berlin;Madrid;Rome;NY;SF;LA;Seoul;Beijing;Tokyo;Sydney.
TEST 4: 
    CITIES:London; Berlin; NY; SF.
    CITIES:Paris; Madrid; Rome.
    CITIES:Berlin; Paris; London.
    CITIES:Sydney;Tokyo;Madrid.
    CITIES:London;Paris;Berlin;Madrid;Rome;NY;SF;LA;Seoul;Beijing;Tokyo;Sydney.
TEST 5: 
    CITIES:Paris; Madrid; Rome.
    CITIES:Madrid;NY;Tokyo.
    CITIES:Sydney;Tokyo;Madrid.
    CITIES:London;Paris;Berlin;Madrid;Rome;NY;SF;LA;Seoul;Beijing;Tokyo;Sydney.
TEST 6: 
TEST 7: 
    CITIES:.
问题的核心是函数“INTERSECT_TABLES”。此函数使用以下语句结果:=A多集相交B不为空。A和B是“表”类型的变量。操作员“。。。多集相交。。。如果表A和表B中至少有一个项目行具有相同的值文本或编号,则无论其在每个表中的顺序或位置如何,is not empty'返回TRUE

说明:

我已经创建了一个名为“table_centers”的临时表,并用一些数据填充了它。为了查询此表,我创建了以下函数:

函数“VARCHAR_TO_TABLE”将字符串VARCHAR转换为“TABLE”类型变量。必须将分隔符作为参数传递,以便由该字符分隔的字符串的每个块都是结果表的一个item=行。这样,无论城市是否用分号分隔,我都可以使用相同的函数;或者用杂烩。此函数使用“regexp_substr”和大容量收集,而不是循环,以获得更好的性能。语句“regexp_substr”中的关键字“level”引用Oracle中的伪列。看

为了执行对“table_centers”的最终查询,我实现了函数“GET_centers”。它只有一个SELECT选项,用于选择字段“cities\U list”中至少有一个与字符串“cities\U input”相同的“table\U centers”记录,该字符串作为参数传递。函数“INTERSECT\U TABLES”对两个字符串进行比较,这些字符串以前通过函数“VARCHAR\U TO\U TABLE”拆分为表

子句“WHERE”中使用函数“INTERSECT_TABLES”,因为过滤必须通过此函数完成。这是因为“表”类型不能在SQL查询中使用。否则,您将得到一个错误:集合类型不能在SQL语句中使用。因此,必须在WHERE子句中使用此函数。此外,布尔类型不能使用,因此,函数“INTERSECT_TABLES”返回数字0或1,不是FALSE或TRUE。

您需要或条件-

with array_bar as (select k from table(array_bar))
select a,b,c 
from table_foo
where c in array_bar 
or    b in array_bar
or    a in array_bar;

也许你正在寻找。例如:

create or replace type number_tt as table of number;

select 'Yes' as member
from   dual
where  1 member of number_tt(1,2,3);

select 'Yes' as subset
from   dual
where  number_tt(2,3) submultiset of number_tt(1,2,3,4);

进一步了解William Robertson的答案,检查一个集合中是否至少有一个成员是另一个集合中的成员:

create or replace type number_tt as table of number;
/

with t1(id, c) as (
  select 1, number_tt(1,2,3) from dual union all
  select 2, number_tt(4,5,6) from dual union all
  select 3, number_tt(7,8,9) from dual
)
select id, 'Yes' Intersects
from   t1
where  c multiset intersect number_tt(1,2,3,8) is not empty;
产生以下结果:

ID  INTESECTS
1   Yes
3   Yes
根据提供的样本数据进行更新。注:从字符串数据到集合的转换留给学生作为练习


是否存在语句结构?示例数据和结果将非常有用。我不确定“它的反面”是什么,或者你的is_contained/is_contained_in操作符会做什么。我无法提供实际数据,但大致是这样的:-有10个城市:伦敦,
NY、巴黎、罗马、马德里、柏林、LA、SF、多伦多、香港-用户选择这10个城市中的一部分,并将它们放置在数组中。纽约;伦敦,一种处理1对N关系的奇怪方式——如果用户选择SF、LA、NY,并且记录的c=Rome;纽约;伦敦然后包含NY和这个记录被选中-如果用户选择香港,巴黎,马德里,和一个记录有C=罗马;纽约;伦敦则不包含任何城市,且此记录未被选中。YCHDZIU:它存在,但不正确,因此我不想将其放在这里。谢谢。谢谢你的快速回复。我会尝试一下,我会把结果放在这里。谢谢你的快速回复。我会尝试一下,我会把结果放在这里。