在NOT IN子句中传递分隔的字符串

问题描述 投票:0回答:2

下面的SQL在概念上复制了我正在尝试解决的问题。尽管传递了NOT IN子句,但返回所有三个记录。

SELECT * FROM (
SELECT 'JACK' AS VALUE FROM DUAL
UNION
SELECT 'JOHN' AS VALUE FROM DUAL
UNION
SELECT 'BOB' AS VALUE FROM DUAL
) WHERE VALUE NOT IN (SELECT 'BOB,JOHN' FROM DUAL);

我有一个表,其中包含一个分隔的字符串,我想将其用作从数据集中排除记录的条件。但是,我遇到的问题是返回的字符串不会分解为其分隔的项目。我想将上述内容翻译为:

SELECT * FROM (
SELECT 'JACK' AS VALUE FROM DUAL
UNION
SELECT 'JOHN' AS VALUE FROM DUAL
UNION
SELECT 'BOB' AS VALUE FROM DUAL
) WHERE VALUE NOT IN ('BOB','JOHN');
oracle plsql
2个回答
0
投票

您可以使用regexp_substr来解决该问题:

SELECT * FROM (
SELECT 'JACK' AS VALUE FROM DUAL
UNION
SELECT 'JOHN' AS VALUE FROM DUAL
UNION
SELECT 'BOB' AS VALUE FROM DUAL
)
WHERE VALUE NOT IN (SELECT regexp_substr('BOB,JOHN','[^,]+', 1, LEVEL) FROM dual CONNECT BY regexp_substr('BOB,JOHN', '[^,]+', 1, LEVEL) IS NOT NULL)

1
投票

'BOB,JOHN'不是两个字符串值的列表,它是一个字符串值,恰好在字符串中包含逗号,并且:

'JACK' = 'BOB,JOHN'
'JOHN' = 'BOB,JOHN'
'BOB'  = 'BOB,JOHN'

都是假的,因此您的查询将返回NOT IN过滤器匹配的所有行。

您可以使用分隔符字符包围值并列出,并测试该值是否不是列表的子字符串,如下所示:

SELECT *
FROM (
  SELECT 'JACK' AS VALUE FROM DUAL UNION ALL
  SELECT 'JOHN' AS VALUE FROM DUAL UNION ALL
  SELECT 'BOB'  AS VALUE FROM DUAL
)
WHERE INSTR( ',' || 'BOB,JOHN' || ',', ',' || value || ',' ) = 0

或者您可以使用用户定义的集合:

CREATE OR REPLACE TYPE stringlist IS TABLE OF VARCHAR2(20);

然后使用MEMBER OF运算符来测试值是否是集合的成员:

SELECT *
FROM (
  SELECT 'JACK' AS VALUE FROM DUAL UNION ALL
  SELECT 'JOHN' AS VALUE FROM DUAL UNION ALL
  SELECT 'BOB'  AS VALUE FROM DUAL
)
WHERE  VALUE NOT MEMBER OF StringList( 'BOB', 'JOHN' );
© www.soinside.com 2019 - 2024. All rights reserved.