web-dev-qa-db-ja.com

同じ列の複数のWHERE条件= val1だが、= val2またはval3ではない

1つの共通列の製品テーブルに結合された、非一意のトランザクションIDを持つテーブルをフィルタリングしようとしています。フィルターは次のようにする必要があります。

equal to :group1 AND
NOT equal to :group2 AND
NOT equal to :group3

私はもともと以下のクエリから始めましたが、AND rk_group <> ____条件。

SELECT COUNT(DISTINCT txn_id)
                    FROM 1_txns
                    INNER JOIN 2_products USING (sku)
                    WHERE rk_group = :group1
                    AND rk_group <> :group2
                    AND rk_group <> :group3
                    ;

私も試しました

SELECT COUNT(DISTINCT txn_id)
                    FROM 1_txns
                    INNER JOIN 2_products USING (sku)
                    WHERE rk_group NOT IN ( :group2, :group3)
                    ;

また、結合とIN()およびNOT IN()の複数の組み合わせを試しましたが、NOTグループが存在するものを含むすべてのチームIDが返されます。

誰かが私を正しい方向に向けることができますか?.

クエリに関連するスキーマ情報:

table 1_txns
(txn_id, sku)

table 2_products
(sku, rk_group)

サンプルデータ

Txn_id, rk_group


------

    1,group1
    1,group2
    2,group1
    3,group1
    3,group3

上記が私のデータであり、group1がmy =グループで、groups2と3が!=グループである場合、行カウント1を返す必要があります。これは、txn id '2'です。これまでに試したすべてのメソッドは、3のカウントを返します。

注:2_productsテーブルには、3つの異なるrk_groupしかありません。

3
Adam Copley

WHERE句は各行に個別に適用され、同じ値がaと等しく、同時にbと等しくないかどうかを確認しても意味がないため、あまり意味がありません。またはc –もちろん、bの場合、cまたはaとは異なります。したがって、代わりに必要なのは、行のグループ全体に条件を適用することです。具体的には、共有する各行グループに同じ_txn_id_。

したがって、GROUP BYを使用し、行のグループに条件を適用するにはHAVINGを使用する必要があります。このクエリは、要件に一致する_txn_id_値のリストを提供します。

_SELECT
    t.txn_id
FROM
    1_txns AS t
    INNER JOIN 2_products AS p USING (sku)
GROUP BY
    t.txn_id
HAVING
    COUNT(p.rk_group = :group1 OR NULL) > 0
    AND COUNT(p.rk_group IN (:group2, group3) OR NULL) = 0
;
_

リストは必要ないようで、アイテムの数だけなので、上記を派生テーブルとして使用して行をカウントします。

_SELECT
   COUNT(*)
FROM
(
    SELECT
        txn_id
    FROM
        1_txns AS t
        INNER JOIN 2_products AS p USING (sku)
    GROUP BY
        t.txn_id
    HAVING
        COUNT(rk_group = :group1 OR NULL) > 0
        AND COUNT(rk_group IN (:group2, group3) OR NULL) = 0
) AS s
;
_

ご覧のとおり、COUNT(DISTINCT ...)は必要ありません。派生テーブルは_txn_id_でグループ化されているため、重複を返すことができません。したがって、正しい結果を得るにはCOUNT(*)で十分です。

この答えで詳しく説明されているように、気づかない場合は、_OR NULL_ビットを使用すると、COUNT関数で一致のみをカウントし、不一致を除外できます。

6
Andriy M

現在の実装の問題は、同じsku/txnsに一致する他の行を表示していないが、そのsku/txnsに一致する別の行に異なるrk_groupがあることだと思います。

_SELECT
    i.sku,
    i.GoodGroup as rk_group
FROM (
    SELECT
        A.sku as sku,
        B.rk_group as GoodGroup,
        COUNT(C.rk_group) as cnt
    FROM
        1_txns as A
        INNER JOIN 2_products as B
            ON A.sku=B.sku
            AND B.rk_group = :group1 --should eliminate anything that isn't in group 1. If MySQL complains about a constant here, drop it to the `WHERE` clause
         LEFT JOIN 2_products as C
            ON A.sku=C.sku 
            AND B.rk_group <> C.rk_group --don't repeat the same entry as previous. This is redundant given the current WHERE clause
     GROUP BY
         A.sku, B.rk_group
     WHERE
         C.rk_group IN (:group2, :group3)
) as i
WHERE
    i.cnt < 1
_

別のレイヤーをその周りにラップしてSELECT COUNT( *stuff from above* )で、必要なエントリ数を取得できます。

0
mpag