2017-02-15 3 views
-2

nenne ich eine Webservice und ich bekomme eine Liste von Codes: A, B, C, D, E, F usw.Abfrage Tabelle mit unterschiedlicher Liste von Variablen wie

In meinem Problem bekomme ich A, B, C.

Es gibt einen Tisch, an dem Sie Sätze mit dem oben genannten Codes erstellen und für jeden Satz können Sie eine bestimmte Nachricht hinzufügen, damit der Endbenutzer die Codes verstehen. Zum Beispiel A bedeutet "ok", B bedeutet "Sie können sich einloggen" Also für die Gruppe A, B könnte eine Nachricht "Sie können sich einloggen" sein. Die Codesätze werden in einer Spalte (Codes) gespeichert.

In meinem Problem Abfrage, die ich die Tabelle, indem Sie die folgende Abfrage verwenden:

Select setid, codes, messagedescr from table1 where setid = (select max(setid) from table1 
         And codes Like '%A%' 
         And codes Like '%B%' 
         And codes Like '%C%'); 

Diese Abfrage eine Zeile findet, aber es ist falsch, die Spalte "Codes" enthält die folgenden Codes: A, B, C, D .

zum Beispiel

:

setid codes  messagedescr 
1  A, B, C, D You can login 
2  B, C, D  You can login for one day 
3  A, C, E  You can login but update your profile 
4  B, C, E, F You cannot login 

ich aus der Webservice die Reihenfolge der Codes nicht wissen, und ich weiß nicht, wie die Codes in der Tabelle gespeichert werden, so hatte ich etwas, ohne zu machen, , Dies warum ich die Likes benutzt habe. Es gibt 25 Codes: A, B, C usw.

Wie kann ich die Abfrage beheben, damit ich die richtige Nachricht finden kann?

Danke!

Update: Vielen Dank für Ihre Antworten und speziell die ausführlicheren Antworten, die zusätzliche Arbeit wie das Erstellen der Tabellen hatten. Die Tabelle könnte aus 10-20 Zeilen bestehen. Ein Fall besteht darin, eine weitere Tabelle für die Codes zu erstellen und sie mit den Set-IDs zu verbinden. Oder der andere Fall besteht darin, die Längen der Codes aus dem Service zu zählen und festzustellen, ob sie mit der Länge in der Tabelle übereinstimmen.

+1

Können Sie bitte einige Beispieldaten und das gewünschte Ergebnis veröffentlichen? (formatierter Text, bitte) – Aleksej

+0

@Tstigtelis Thanasis, Wenn Sie A, B, C schreiben bedeutet Nachricht, die Sie wollen dispaly.ie A-Nachricht oder B-Nachricht oder C-Nachricht, was ist Ihre Priorität. – Mansoor

+1

Dies ist eine Folge des schlechten DB-Designs, das mit Ihnen aufholt. Speichern Sie nicht mehrere Codes in einer einzelnen Spalte. Verwenden Sie eine separate Tabelle. – dasblinkenlight

Antwort

1

Wenn ich Ihr Bedürfnis gut verstehe, könnte dies ein Weg sein.

Sagen Sie bitte eine Tabelle wie folgt aus:

with inputData(codes) as (
    select listagg(trim (regexp_substr(input_codes, '[^,]+', 1, level))) within group (order by trim (regexp_substr(input_codes, '[^,]+', 1, level))) 
    from (select 'A, D, C, B' as input_codes from dual) /* the input string */ 
    CONNECT BY instr(input_codes, ',', 1, level - 1) > 0 
)  
select * 
from inputData 
    inner join (
       select listagg(trim (regexp_substr(codes, '[^,]+', 1, level))) 
         within group (order by trim (regexp_substr(codes, '[^,]+', 1, level))) as codes, 
         messagedescr 
       from yourTable 
       CONNECT BY instr(codes, ',', 1, level - 1) > 0 
        and prior setId = setId 
        and prior sys_guid() is not null 
       group by setId, messagedescr 
       ) 
     using (codes) 

Die Idee hier ist Ihre Eingabestring in vielen Reihen zu spalten, und dann aggregieren die resultierende:

create table yourTable(setid, codes, messagedescr) as ( 
    select 1,  'A, B, C, D', 'You can login' from dual union all 
    select 2,  'B, C, D' , 'You can login for one day' from dual union all 
    select 3,  'A, C, E' , 'You can login but update your profile' from dual union all 
    select 4,  'B, C, E, F', 'You cannot login' from dual 
). 

Dies ist ein Weg sein könnte, Zeilen in alphabetischer Reihenfolge, wenden Sie dann die gleiche Reihenfolge auf die Werte in der Tabelle an und überprüfen Sie dann, ob die geordneten Strings gleich sind.

Dieser Teil aufzuspalten, Ordnung und aggregieren die Eingabewerte verwendet, so dass das Ergebnis eine geordnete Zeichenfolge ist:

select listagg(trim (regexp_substr(input_codes, '[^,]+', 1, level))) within group (order by trim (regexp_substr(input_codes, '[^,]+', 1, level))) 
    from (select 'A, D, C, B' as input_codes from dual) /* the input string */ 
    CONNECT BY instr(input_codes, ',', 1, level - 1) > 0 

gibt:

ABCD 

Dieser Teil der tun, verwendet wird, gleiche auf dem Tisch:

select listagg(trim (regexp_substr(codes, '[^,]+', 1, level))) 
     within group (order by trim (regexp_substr(codes, '[^,]+', 1, level))) as codes, 
     messagedescr 
from yourTable 
CONNECT BY instr(codes, ',', 1, level - 1) > 0 
    and prior setId = setId 
    and prior sys_guid() is not null 
group by setId, messagedescr 

gibt:

Die Verknüpfung zwischen diesen Teilergebnissen ist recht einfach und überprüft einfach, ob in Ihrer Tabelle ein Wert (geordnet) vorhanden ist, der der (geordneten) Eingabezeichenfolge entspricht.

1

Oracle-Setup:

Beginnen Sie mit einer einfachen Funktion zu split a delimited string in einer Sammlung:

CREATE OR REPLACE TYPE stringlist AS TABLE OF VARCHAR2(20) 
/

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

und einige Beispieldaten:

CREATE TABLE your_table(setid, codes, messagedescr) 
    SELECT 1, 'A,B,C,D', 'You can login' FROM DUAL UNION ALL 
    SELECT 2, 'B,C,D', 'You can login for one day' FROM DUAL UNION ALL 
    SELECT 3, 'A,C,E', 'You can login but update your profile' FROM DUAL UNION ALL 
    SELECT 4, 'B,C,E,F', 'You cannot login' FROM DUAL; 

Dann können Sie tun (vorbei an Ihre Eingabe C,A,B - in beliebiger Reihenfolge - als Bindeparameter :your_code):

SELECT * 
FROM (
    SELECT * 
    FROM your_table 
    WHERE split_string(codes) SUBMULTISET OF split_String(:your_code) 
    ORDER BY setid DESC 
) 
WHERE ROWNUM = 1; 

und es wird die Zeile mit dem höchsten übereinstimmenden Satz von Codes ausgegeben.

Hinweis: Im obigen Beispiel wird davon ausgegangen, dass Sie alle Codes in der Tabelle mit Codes in Ihrer Eingabezeichenfolge übereinstimmen müssen. Wenn Sie nur mindestens eine Übereinstimmung benötigen, können Sie Folgendes verwenden:

WHERE split_string(codes) MULTISET INTERSECT split_String(:your_code) IS NOT EMPTY 
Verwandte Themen