2012-11-05 32 views
5

我有兩個表解析MySQL中使用逗號作爲分隔符

表1與用戶逗號列表分隔

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

表2

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

我需要找到一個在表1的用戶爲每個名稱,但不是在table2中(當用戶ID到名稱對存在於table2中但不存在於CSV1中時,將不存在實例)。

輸出應該

Name UserID 
abc  D 
def  C 

我可以用PHP這樣做,但有沒有辦法這可以通過查詢來完成?我不知道從哪裏開始以防我作爲查詢執行此操作。我可以使用逗號作爲分隔符在MySQL中解析嗎?

+0

'我需要找到位於table1中的用戶,而不是**每個名稱**而不是table2。但是table1中的'D'不在**每個Name **中。 'D'只在'abc'中。那麼它是如何產生你想要的輸出呢? – hims056

+0

我的意思是每個名稱UserID對.. – Ank

+3

你已經非規範化數據庫中的數據。我建議你做的是運行一個PHP腳本來規範化數據,並將結果保存在數據庫的標準化數據庫中。這樣,這個特定的查詢和所有未來的查詢將會簡單得多。通常,最好避免存儲在數據庫字段中的逗號分隔值。有關數據庫規範化的更多信息,請訪問:http://databases.about.com/od/specificproducts/a/normalization.htm –

回答

3

我將測試數據插入到SQLFiddle中的測試模式中,並運行以下查詢。

這裏的鏈接到SQLFiddle與試驗和積極的成果: http://sqlfiddle.com/#!2/83dfd/4/0

這裏的查詢:

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; 

如果table1中有很長的列寬您可能需要展開「INDEX_TABLE 「子查詢。你可以在這個鏈接上覆制並粘貼代碼:
http://www.experts-exchange.com/Database/MySQL/A_3573-A-MySQL-Tidbit-Quick-Numbers-Table-Generation.html

+1

完整的外連接檢查兩個表中缺少的數據。我剛剛意識到你只有可能從他們丟失的數據。同樣的查詢邏輯仍然可以工作,但是你可以在上面的代碼中用右外連接 –

+0

代替完整的外連接或者......你可以用'where not exists'替換'join'語法和當前where子句...)'條款。這可能是最優雅的方式,可能會更快一些。 –

+0

由於意識到你不想從兩個表中遺漏結果,所以也會發生這樣的情況,它會簡單得多,而且也一樣。 SELECT NAME,USERID FROM TABLE2 WHERE NOT EXISTS(SELECT FROM TABLE1 WHERE TABLE1.NAME = TABLE2.NAME AND( TABLE1.USERID LIKE '%' + TABLE2.USERID + '%' 或TABLE1.USERID LIKE TABLE2.USERID +',%' OR TABLE1.USERID LIKE'%,'+ TABLE2.USERID ) ); –

0

如果你的表是固定的(你想要在這些表上工作),那麼設計一個類來從它們中讀取數據,而不是直接從這些預定義的表中保存設置數據;讓你的對象在你的應用程序域中處理讀取的數據,以獲得全面的可訪問性。 :-D

+0

感謝您的回覆。我可以編寫一個PHP腳本來解析用戶列。不過,我創建了一個JavaScript/PHP模塊,它將SQL查詢作爲輸入並以有序格式顯示結果。我想知道是否可以查詢這個問題,我可以適應我的模塊,並直接得到輸出。我希望它是有道理的! – Ank

+0

:-D太注意了。 –