PL/sqloracle。实现包含IS_运算符的最佳方法
我是新手,所以这个问题可能已经被问过一两万次了,但它在知识数据库中是不可查找/搜索的 在Oracle PL/SQL中,通常会进行如下查询: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
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:它存在,但不正确,因此我不想将其放在这里。谢谢。谢谢你的快速回复。我会尝试一下,我会把结果放在这里。谢谢你的快速回复。我会尝试一下,我会把结果放在这里。