0

と の 2 つのテーブルがuserありprojects、2 つのテーブルは 1 対多の関係にあります。
projectsテーブルにはstatus、ユーザーのプロジェクト ステータスのフィールドがあります。

status次のいずれかになります。

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

ユーザーを次の 2 つのカテゴリに分類したいと考えています。

  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ユーザーがステータスがoverduecompleteまたはのプロジェクトを持っている場合failed、そのユーザーは の両方の条件をCASE満たしているため、2 回記録されます。

launchedステータスのプロジェクトを持つユーザーが自分のuser_categoryセットを に取得するクエリを提案してください1。に対して同じユーザーを繰り返さないでくださいuser_category 2

4

2 に答える 2

4

クエリは、いくつかの理由で、おそらくあなたが思っていることをしていないでしょう

  • ありDISTINCT、あります。と違いはありません。括弧は単なるノイズです。DISTINCTON(col1, col2)
    DISTINCT (u.*)DISTINCT u.*

  • AND演算子の優先順位ORに従って前にバインドします。一緒に編集された条件の周りに括弧を使用したいと思いますか?それとも、そのまま必要ですか?ただし、どのような場合でも、句全体を括弧で囲む必要はありません。ORWHERE

  • あなたの表現LOWER(u.username) LIKE '%%%'は意味がありません。null以外のすべての文字列が修飾されます。に置き換えることができますu.username IS NOT NULL。何か違うものが欲しいのかな?

  • Postgresは文字列処理で大文字と小文字を区別します。'launched'などと記述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

この関連する質問の詳細な説明:

の代わりに2つのEXISTS半結合DISTINCT ONし、より高速になる可能性がありCASEます。

SELECT u.*
     , CASE WHEN EXISTS (
          SELECT 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;
于 2013-03-17T20:24:39.483 に答える
1

結果に使用できMIN()ますCASE。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>
...

「launched」は1を与えるため、MIN()を使用すると、単一の結果が強制されるだけでなく、他の状態よりも「launched」が優先されます。

于 2013-03-17T20:24:07.600 に答える