0

我有兩個表:userprojects,兩者之間有一對多的關係。
projects表的字段status包含用戶的項目狀態。PostgreSQL查詢返回多行而不是一個

status可以是一個:

launched, confirm, staffed, overdue, complete, failed, ended 

我想在兩個類別來分類用戶:具有項目

  1. 用戶launched階段
  2. 用戶具有比launched狀態等項目。

我使用下面的查詢:

SELECT DISTINCT(u.*), CASE 
    WHEN p.status = 'LAUNCHED' THEN 1 
    ELSE 2 
    END as user_category 
FROM users u 
LEFT JOIN projects p ON p.user_id = u.id 
WHERE (LOWER(u.username) like '%%%' 
    OR LOWER(u.personal_intro) like '%%%' 
    OR LOWER(u.location) like '%%%' 
    OR u.account_status != 'DELETED' 
AND system_role=10 AND u.account_status ='ACTIVE') 
ORDER BY set_order, u.page_hits DESC 
LIMIT 10 
OFFSET 0 

我面對重複記錄用於以下情形:

如果用戶具有狀態launched以及overduecompletefailed項目,那麼該用戶被記錄兩次,因爲CASE中的條件都滿足該用戶。

請建議查詢,其中有launched狀態的任何項目的用戶將其user_category設置爲1user_category 2不應該重複相同的用戶。

+0

'distinct'是**不**的功能。 –

回答

1

您可以在CASE結果使用MIN(),似乎跌落DISTINCT將是一個明智的選擇:

SELECT u.*, MIN(CASE 
WHEN p.status = 'LAUNCHED' THEN 1 
ELSE 2 
END) as user_category 
... 
GROUP BY <list all columns in the users table> 
... 

由於「推出」給出了一個1,使用MIN()不僅會迫使一個結果,但也會優先於其他州的「推出」。

+0

我不認爲這足以解決這個爛攤子。 –

+0

@ErwinBrandstetter你爲什麼這麼認爲?這對我來說似乎相當直接。 – Bohemian

+0

如果你放棄DISTINCT(並解決其他問題),GROUP BY將是一個明智的選擇。 –

3

該查詢可能不會做你覺得它做什麼的許多原因

  • DISTINCT並有DISCTINCTON(col1, col2)
    DISTINCT (u.*)DISTINCT u.*沒有區別。括號只是噪音。

  • AND根據operator precedenceOR之前結合。我懷疑你想圍繞條件使用括號還是一起?或者你需要它的方式?但是在任何情況下,你都不需要圍繞整個WHERE條款的括號。

  • 您的表情LOWER(u.username) LIKE '%%%'沒有任何意義。每個非空字符串都有資格。可以用u.username IS NOT NULL代替。我懷疑你想要不同的東西?

  • PostgreSQL是區分大小寫在字符串處理中。你寫的status被「啓動」等,但在你的查詢中使用「LAUNCHED」。它會是什麼?

  • 由於問題使讀者不明確,因此缺少一些表格資格。我的身材如同鋸齒一樣填滿。

一切放在一起就可能工作是這樣的:

SELECT DISTINCT ON (u.set_order, u.page_hits, u.id) 
     u.* 
     ,CASE WHEN p.status = 'LAUNCHED' THEN 1 ELSE 2 END AS user_category 
FROM users   u 
LEFT JOIN projects p ON p.user_id = u.id 
WHERE LOWER(u.username)  LIKE '%%%' -- ??? 
    OR LOWER(u.personal_intro) LIKE '%%%' 
    OR LOWER(u.location)  LIKE '%%%' 

    OR u.account_status != 'DELETED'  -- with original logic 
    AND u.system_role = 10 
    AND u.account_status = 'ACTIVE' 
ORDER BY u.set_order, u.page_hits DESC, u.id, user_category 
LIMIT 10 
在此相關的問題

詳細說明:

這種替代可能是快呃有兩個EXISTS semi-joins代替DISTINCT ONCASE ...

SELECT u.* 
     ,CASE WHEN EXISTS (
     SELECT 1 FROM projects p 
     WHERE p.user_id = u.id AND p.status = 'LAUNCHED') 
     THEN 1 ELSE 2 END AS user_category 
FROM users u 
WHERE 
    ( LOWER(u.username)  LIKE '%%%' -- ??? 
    OR LOWER(u.personal_intro) LIKE '%%%' 
    OR LOWER(u.location)  LIKE '%%%' 
    OR u.account_status != 'DELETED'  -- with alternative logic? 
    ) 
AND u.system_role = 10 -- assuming it comes from users ??? 
AND u.account_status = 'ACTIVE' 
AND EXISTS (SELECT 1 FROM projects p WHERE p.user_id = u.id) 
ORDER BY u.set_order, u.page_hits DESC 
LIMIT 10; 
相關問題