2013-11-25 112 views
0

我會盡量直接指向我在這裏試圖完成的任務......MySQL:查詢中的條件語句

我有一個查詢,但最近我發現了一個問題。現在,我可以簡單地用PHP解決這個問題,但我知道它可以在MySQL中以某種方式完成......我只是不知道如何。所以這是怎麼回事:

我有一個USERS表和一個SERVICES表。用戶可以擁有多個服務(每個服務彼此完全獨立),每個服務都有一個稱爲「狀態」的字段。狀態定義服務當前的狀態:活動/未活動

當您轉到「管理用戶」頁面時,會調用該查詢,其中每個用戶都被分成它所屬的類別。對於這個例子,它將是:活動用戶|取消激活的用戶|其他用戶(根本沒有任何服務計劃的用戶)。

所以我停用用戶的查詢可以歸結爲:

SELECT DISTINCT u.* FROM users u LEFT JOIN services s ON s.assignedto=u.id WHERE s.status!=1 

聲明的偉大工程,但是,如果客戶有2個服務計劃,其中一個被激活,一個被停用,那麼他將出現在停用列表以及激活的列表。該聲明需要一個條件,如果用戶還有激活的服務計劃,它將從查詢中排除該用戶。現在,我有一些用戶陷入停用的應用程序中,而這些用戶不應該在那裏。

無論如何,先謝謝您!

回答

2

您可以用not exits()重寫查詢作爲@GarethD建議。

另一種方法有一點,如果它不能很好地擴展可以通過子句是一組,例如:

SELECT u.* 
FROM users u 
LEFT JOIN services s ON s.assignedto=u.id 
GROUP BY u.id 
HAVING max(s.status) <> 1 

最好的選擇,不過,將是一個額外的領域。如果您將status字段添加到users,則可以直接編制索引並進行查詢。你可以使用觸發器來維護它,但是,就我個人而言,這是一種罕見的情況,我發現在應用程序中維護它是一種更好的方法。 (基本上,你永遠不知道什麼時候你需要快速將用戶標記爲非活動狀態,而不會混淆其他數據庫表。)

+0

+1 for group by。 –

+0

太棒了。是的,我最初想到了這種方法,但依靠一個領域來確定用戶的不活動(我覺得)是讓自己在某個時候失敗。對於任何情況下,當服務變爲停用(付款失敗,手動停用等)時,我必須勾選該字段以停用。雖然,這個SQL查詢解決了這一切:)。謝謝! – user0000001

+1

@Chris:長期來看,出於性能原因,這是更好的選擇。如果您希望它具有防故障功能,請使用觸發器進行管理,並添加一個單獨的字段以防需要手動覆蓋它。通過這種方式你將不會有失誤的機會,而索引是一種獎勵。 –

0

可以使用NOT EXISTS排除有活躍業務的用戶:

SELECT u.* 
FROM users u 
WHERE NOT EXISTS 
     ( SELECT 1 
      FROM Services s 
      WHERE s.assignedto=u.id 
      AND  s.status = 1 
     ); 

爲了讓你的罪名,我想你需要的東西是這樣的:

SELECT COUNT(CASE WHEN s.ActiveServices > 0 THEN 1 END) AS ActiveUsers, 
     COUNT(CASE WHEN s.ActiveServices = 0 THEN 1 END) AS DeactivatedUsers, 
     COUNT(CASE WHEN s.assignedto IS NULL THEN 1 END) AS OtherUsers 
FROM users u 
     LEFT JOIN 
     ( SELECT s.assignedto, 
        COUNT(CASE WHEN s.status = 1 THEN 1 END) AS ActiveServices 
      FROM Services s 
      GROUP BY s.assignedto 
     ) s 
      ON s.assignedto = u.ID 

我剛剛記得在MySQL中NOT EXISTS is not as efficient as LEFT JOIN/IS NULL,丹尼斯也指出NOT EXISTS不會規模好。該LEFT JOIN的做法是:

SELECT u.* 
FROM Users u 
     LEFT JOIN Services s 
      ON s.assignedto = u.id 
      AND s.status = 1 
WHERE s.assignedto IS NULL;