2012-11-05 12 views
5

Mam dwie tabeleParse w MySQL za pomocą przecinka jako separatora

tabela1 z listą użytkowników oddzielonych przecinkami

Name UserID 
abc  A,B,C,D 
def  A,B,C 

Tabela 2

Name UserID 
abc A 
abc B 
abc C 
def A 
def B 

muszę znaleźć użytkowników, którzy w tabela1 dla każdej nazwy, ale nie w tabeli 2 (Nie będzie nigdy przypadku, gdy para ID użytkownika jest obecna w tabeli 2, ale nie w tabeli 1 jako CSV).

Wyjście powinno być

Name UserID 
abc  D 
def  C 

mogę to zrobić z PHP, ale czy istnieje sposób można to zrobić za pomocą kwerendy? Nie jestem pewien, od czego zacząć w przypadku, gdy robię to jako zapytanie. Czy mogę analizować w MySQL używając przecinka jako ogranicznika?

+0

'Muszę znaleźć użytkowników, którzy są w tabeli1 dla ** każdej nazwy **, ale nie w tabeli2'. Ale 'D' w tabeli1 nie jest w ** każdej nazwie **. 'D' jest tylko w' abc'. W takim razie, w jaki sposób powstaje pożądany efekt? – hims056

+0

Co mam na myśli, to każda nazwa UserID pair .. – Ank

+3

Masz denormalizowane dane w bazie danych. Polecam ci wykonanie skryptu PHP w celu normalizacji danych i zapisanie wyników w znormalizowanym dla twojej bazy danych. W ten sposób to konkretne zapytanie i wszystkie przyszłe zapytania będą znacznie prostsze. Ogólnie dobrze jest unikać wartości rozdzielanych przecinkami przechowywanych w polach bazy danych. Przeczytaj więcej na temat normalizacji baz danych tutaj: http://databases.about.com/od/specificproducts/a/normalization.htm –

Odpowiedz

3

Podłączyłem danych testowych do schematu testu w SQLFiddle i prowadził kwerendę, która podąża.

Oto link do SQLFiddle z testem i pozytywnych wyników: http://sqlfiddle.com/#!2/83dfd/4/0

oto zapytanie:

SELECT 
COALESCE(NORMALIZED_TABLE1.NAME, TABLE2.NAME) AS NAME, 
COALESCE(NORMALIZED_TABLE1.USERID, TABLE2.USERID) AS USERID 
FROM (
    SELECT NAME, 
    SUBSTRING(
      USERID 
      FROM CASE 
       WHEN INDEX_TABLE.POS = 1 THEN 1 
       ELSE INDEX_TABLE.POS + 1 
       END 
      FOR CASE LOCATE(',', USERID, INDEX_TABLE.POS + 1) 
       WHEN 0 THEN CHARACTER_LENGTH(USERID) + 1 
       ELSE LOCATE(',', USERID, INDEX_TABLE.POS + 1) 
       END 
       - CASE 
       WHEN INDEX_TABLE.POS = 1 THEN 1 
       ELSE INDEX_TABLE.POS + 1 
       END 
    ) AS USERID 
    FROM TABLE1 
    INNER JOIN (
      SELECT @rownum:[email protected]+1 POS 
      FROM (
      SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 
      UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 
      UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 
     ) a, (
      SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 
      UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 
      UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 
     ) b, (
      SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 
      UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 
      UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 
     ) c, (SELECT @rownum:=0) r 
    ) INDEX_TABLE 
    ON INDEX_TABLE.POS <= CHAR_LENGTH(TABLE1.USERID) 
    AND (
      INDEX_TABLE.POS = 1 
      OR SUBSTRING(USERID FROM INDEX_TABLE.POS FOR 1) = ',' 
    ) 
) AS NORMALIZED_TABLE1 
LEFT OUTER JOIN TABLE2 
ON NORMALIZED_TABLE1.NAME = TABLE2.NAME 
AND NORMALIZED_TABLE1.USERID = TABLE2.USERID 
WHERE TABLE2.NAME IS NULL; 

Jeśli masz bardzo dużo szerokość kolumny w tabela1 może trzeba rozwinąć „INDEX_TABLE "podzapytanie. Możesz go skopiować i wkleić z kodem pod tym linkiem:
http://www.experts-exchange.com/Database/MySQL/A_3573-A-MySQL-Tidbit-Quick-Numbers-Table-Generation.html

+1

pełne sprzężenie zewnętrzne sprawdza brakujące dane z obu tabel. Właśnie zdałem sobie sprawę, że masz tylko możliwe brakujące dane od nich. Ta sama logika zapytań nadal by działała, ale można by zastąpić w powyższym kodzie pełne sprzężenie zewnętrzne z prawym złączem zewnętrznym –

+0

LUB ... można zastąpić składnię "dołącz" i obecną klauzulę where z "gdzie nie istnieje (...) ".Prawdopodobnie byłaby to najbardziej elegancka droga, może też być nieco szybsza. –

+0

Odkąd zdał sobie sprawę, że nie chcesz pominąć wyników z obu tabel, okazało się, że byłoby to o wiele prostsze i równie dobrze. WYBIERZ NAZWA, identyfikatora Z Tabela 2 GDZIE nie istnieje ( wybrania 0 Z Tabela 1 GDZIE TABLE1.NAME = TABLE2.NAME I ( TABLE1.USERID LIKE '%' + TABLE2.USERID + '%' LUB TABELA1.NASYPOWNIK JAK TABELA2. ZAZNACZNIK + ',%' LUB TABELA1. ZAZNACZNIK JAK "%," + TABELA2.USERID ) ); –

0

Jeśli tabela jest stała (jesteś chciał pracować na tych tabel), a następnie zaprojektować klasę do odczytu danych z nich zamiast bezpośredniego zapisywania danych z tych zestawów predefiniowanych tabelach; pozwól swojemu obiektowi przetwarzać dane odczytane na żywo w całej domenie aplikacji, aby uzyskać pełną dostępność. :-D

+0

Dzięki za odpowiedź. Mogę bardzo dobrze napisać skrypt PHP do analizy kolumny użytkownika. Jednak stworzyłem moduł JavaScript/PHP, który przyjmuje zapytanie SQL jako dane wejściowe i wyświetla wyniki w zamówionym formacie. Zastanawiam się, czy może istnieć zapytanie dotyczące tego problemu, które można dopasować do mojego modułu i bezpośrednio uzyskać dane wyjściowe. Mam nadzieję, że to ma sens! – Ank

+0

:-D zbyt uważne. –

Powiązane problemy