2016-06-07 30 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