2016-10-10 6 views
1

レコードが重複している場合は、フィールドにデータが格納されるテーブルがあります。コードはすでに実行されており、重複を適切にチェックして作業しています。ヌルでないフィールド別のMYSQLグループ化

表は次のようになります。

id | dupe_ids | id_subscription 
    1  NULL   5343 
    2  3, 4   5343 
    3  2, 4   5343 
    4  2, 3   5343 
    5  NULL   5343 
    6  7   5343 
    7  6   5343 

問合せは、エントリの数のカウントを返しますが、グループに重複したIDを必要とすべきです。エントリを持つレコードを1つのカウントにグループ化するクエリが必要ですが、何とかその重複に基づいています。上記の例のサブスクリプション5343のカウントでは、カウントは4になります。レコード2は3と4がスキップまたはグループ化され、レコード6は1とみなされ、レコード7はグループ化またはスキップされます。

クエリは次のようになります。dupe_idsの値が数値id値のリストで、リストが常にある場合、最低値はリストの最初のもので、「順番に」

SELECT app.id_subscription, app.id_site, app.id_customer, COUNT(*) AS app_count, site.url 
FROM web_manager.app, web_manager.site 
WHERE app.id_customer = :wm_id 
AND (app.received_at BETWEEN :sdate AND :edate) 
AND app.id_site = site.id 
AND app.dupe_ids IS NULL 
GROUP BY app.id_subscription 
ORDER BY app_count DESC 
+0

あなたの質問はありますか? – Barmar

+1

私はこの質問を「このMonty Python-esqueテーブルに対して実行するSQLステートメントとは何ですか?」という返事を返します。「...」と言いました。そして、主は言われました。「あなたは聖なるピンあなたは3つに数え、それ以上はないではない.3つはあなたの数であり、計数の数は3でなければならない。あなたは数えない。 3つの5つが出てきます – spencer7593

+0

「AND app.dupe_ids IS NULL」を「AND app.dupe_ids IS NOT NULL」に変更してください。その後、正しいカウントを取得します。 – Barmar

答えて

0

汚れた溶液として...

0の代わりにLEAST(a.id,SUBSTRING_INDEX(a.dupe_ids,',',1)+0)の定数を置き換えるために、私の元の回答(下)のクエリが変更されました。

dupe_idsリストから最初の値を取り出し、それを数値コンテキストで評価し、その数値をその行の数値idと比較し、その2つのうち小さい方を返します。

SELECT COUNT(DISTINCT IF(a.dupe_ids IS NULL,a.id,LEAST(a.id,SUBSTRING_INDEX(a.dupe_ids,',',1)+0))) AS my_funky_cnt 
    , a.id_subscription 
    FROM web_manager.app a 
    JOIN web_manager.site s 
    ON s.id = a.id_site 
WHERE ... 
GROUP BY a.id_subscription 

再びmy_funky_cnt DESC

BY ORDER、実際に式によって返されているかを見るためにGROUP BYや集計を、削除...

SELECT a.id 
     , a.dupe_ids 
     , a.id_subscription 
     , IF(a.dupe_ids IS NULL,a.id,LEAST(a.id,SUBSTRING_INDEX(a.dupe_ids,',',1)+0)) AS expr 
    FROM web_manager.app a 
    JOIN web_manager.site s 
    ON s.id = a.id_site 
    WHERE ... 
    ORDER BY a.id_subscription, a.dupe_ids IS NULL, a.id 

我々はそれを期待します戻り値:

id | dupe_ids | id_subscription | expr 
    2  3, 4   5343   2  -- id=2 is less than fv=3 
    3  2, 4   5343   2  -- fv=2 is less than id=3 
    4  2, 3   5343   2  -- fv=2 is less than id=4 
    6  7   5343   6  -- id=6 is less than fv=7 
    7  6   5343   6  -- fv=6 is less than id=7 
    1  NULL   5343   1 
    5  NULL   5343   5 

のでGROUP BY id_subscriptionCOUNT(DISTINCT expr)は、数値の文脈において、その最初の値を評価し、(これはテストしていない)、このアプローチは、(リストの最初の値)が最初にリスト最小のID値を有するdupes_idに依存

の数を返しますその行の値をidと比較します。

dupe_idsが空の文字列、またはカンマで始まる、または最初の非空白文字が数値として解釈できない場合は、その後、expr0を返すために起こっています。

EDIT

オリジナルの答えは(下記)与えられたid_subscriptionための非NULL値を持つ行のすべてを崩壊に基づいていた...質問が追加、更新された3の数を返します一緒に崩壊してはならないNULL以外の値を持つ行の例"count"の戻り値が4になりました。元の応答のクエリは3のカウントを返します。

NULL値がdupe_idsの行の数を取得するのは簡単です。

スティッキーウィケットたちは「カンマ区切りリスト」を扱っていなかった場合、これは容易になるだろう

id dupe_ids 
---- -------- 
2  '3,4' 
3  '2,4' 
4  '2,3' 
6  '7' 
7  '6' 

... dupe_ids列、ID値をカンマで区切ったリストの奇妙な内容です値の代わりに、別のテーブルに、行への外部キー参照があった場合。または、「重複している」行を識別するために、dupe_ids列以外の基準がある場合。

しかし、これは質問された質問ではありませんでした。質問は、がコンマで区切られたリストを格納することを避けるほうがよいか尋ねなかった。より良いアプローチがあるかどうか。

この質問は、カンマで区切られたリストを扱っています。 (なぜカンマで区切られたリストを避けることを強く推奨するのかの例として役立ちます)。

私たちは、その後、我々はCOUNT(DISTINCT expr)を使用することができ

id dupe_ids expr 
---- -------- ------ 
2  '3,4'  '2,3,4' 
3  '2,4'  '2,3,4' 
4  '2,3'  '2,3,4' 
6  '7'  '6,7' 
7  '6'  '6,7' 

...私たちは行に同じ値を持っていたように、一緒に、id値とともにdupe_idsの値を持つ式を持っていた場合私たちが帰ってきた時の復帰を得る醜い部分はexprという値になっています。 idを先頭に追加するか、またはdupe_idsに追加するのは簡単ですが、結果の文字列値は同一ではありません。リストは異なる順序になります。

iddupe_idsの内容に基づいて、exprの値を返すためのMySQLには、単純な組み込み関数はありません。

ORIGINAL ANSWER

私はかかるだろうなアプローチは、式を使用し、その異なる値をカウントすることです。

dupe_idsがnullの場合、一意の値を返します。 idがテーブル内で一意の場合は、その列の値を使用します。 dupe_idsがNULLでない場合は、有効なid値ではない定数で置き換えます。 idの値が正の整数であるとすると、0または負の値を使用します。一例として、

:私は最初のGROUP BYおよび集計せずにクエリを実行して、 "作業" された発現を確認したい

SELECT COUNT(DISTINCT IF(a.dupe_ids IS NULL,a.id,0)) AS my_funky_cnt 
     , a.id_subscription 
    FROM web_manager.app a 
    JOIN web_manager.site s 
    ON s.id = a.id_site 
    WHERE ... 
    GROUP BY a.id_subscription 
    ORDER BY my_funky_cnt DESC 

...

SELECT a.id 
     , a.dupe_ids 
     , a.id_subscription 
     , IF(a.dupe_ids IS NULL,a.id,0) AS derived_col 
    FROM web_manager.app a 
    JOIN web_manager.site s 
    ON s.id = a.id_site 
    WHERE ... 
    ORDER BY a.id_subscription, a.dupe_ids IS NULL, a.id 

我々が期待しますそれは戻ります:

id | dupe_ids | id_subscription | derived_col 
    1  NULL   5343   1 
    2  3, 4   5343   0 
    3  2, 4   5343   0 
    4  2, 3   5343   0 
    5  NULL   5343   5 

をそうdupe_ids null以外の同じ値を持っているとのすべての行、およびNULL dupe_idsの行には一意の値があります。

そしてその式のCOUNT(DISTINCTは3を返します。

+0

あなたは彼の質問を理解しましたか? – Barmar

+0

@Barmar:当初ではありません。私が3を得る唯一の方法は、 'dupe_id 'のNULLでない値を持つすべての行を単一の行に"崩壊 "することでした。 (私はBill Karwinの本をチェックして、このアンチパターンの章があるかどうかを確認する必要があります) – spencer7593

+0

彼のクエリでは、 'AND dupe_ids IS NOT NULL'からのものではありませんか? – Barmar

関連する問題