2016-06-07 29 views
0

所以我一直在寻找,但是我无法在任何地方找到我需要的帮助。Oracle/SQL - 从字符串中选择缺失值

我有这样的查询来搜索缺少了什么价值观的具体名单,但除了发现如果确实有缺少什么,我需要知道缺少哪个值:

SELECT t1.*, 
FROM tabl1 t1 
WHERE col1 IN ('31' , '32') 
AND NOT (valList LIKE '%;13;%' AND valList LIKE '%;19;%') 
OR NOT (valList LIKE '%;15;%'); 

所以,如果列表包含;13;15;我需要知道缺少的值是19.

在此先感谢! RMGz

回答

0

您可以使用Oracle的Collections:

Oracle Setup

集合存储许多字符串:

CREATE TYPE VARCHAR2_TABLE AS TABLE OF VARCHAR2(4000); 
/

一个辅助功能列表拆分成字符串的集合:

CREATE OR REPLACE FUNCTION split_String(
    i_str IN VARCHAR2, 
    i_delim IN VARCHAR2 DEFAULT ',' 
) RETURN VARCHAR2_TABLE DETERMINISTIC 
AS 
    p_result  VARCHAR2_TABLE := VARCHAR2_TABLE(); 
    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 
    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; 
/

查询

SELECT * 
FROM (
    SELECT t.*, 
     varchar2_table('15', '13', '19') 
      MULTISET EXCEPT split_string(TRIM(BOTH ';' FROM valList), ';') 
      AS missing_values 
    FROM tabl1 t 
) 
WHERE missing_values IS NOT EMPTY; 

你可以然后通过将许多(或几个)值传入集合来修改查询(甚至可以使用pass a collection as a bind value),您不必添加多个CASE语句。

+0

正是我需要的! – RMGz

1

您的数据格式非常差。你不应该把东西(尤其是数字)的列表存储为字符串。

但考虑到坏的数据格式,可以使用case给名单:

SELECT t1.*, 
     ((CASE WHEN valList NOT LIKE '%;13;%' THEN '13;' ELSE '' END) || 
     (CASE WHEN valList NOT LIKE '%;19;%' THEN '19;' ELSE '' END) || 
     (CASE WHEN valList NOT LIKE '%;15;%' THEN '15;' ELSE '' END) 
     ) as MissingIds 
FROM tabl1 t1 
WHERE col1 IN ('31' , '32') AND 
     NOT (valList LIKE '%;13;%' AND valList LIKE '%;19;%') OR 
     NOT (valList LIKE '%;15;%'); 

你甚至可以使用子查询,这样你就不必再重复的逻辑:

SELECT t1.* 
FROM (SELECT t1.*, 
      ((CASE WHEN valList NOT LIKE '%;13;%' THEN '13;' ELSE '' END) || 
       (CASE WHEN valList NOT LIKE '%;19;%' THEN '19;' ELSE '' END) || 
       (CASE WHEN valList NOT LIKE '%;15;%' THEN '15;' ELSE '' END) 
      ) as MissingIds 
     FROM tabl1 t1 
     WHERE col1 IN ('31' , '32') 
    ) t1 
WHERE MIssingIds IS NOT NOT NULL 
+0

是的,我知道数据格式是可怕的 - 但我正在一个现有的项目上工作,我坚持原样。 感谢您的帮助!我会让你知道,如果出了问题;) RMGz – RMGz

+0

正如在选定的答案中提到的,我有情况下,我将不得不使用太多的“案件”陈述... 感谢您的支持! RMGz – RMGz