1

タイトルがややこしいので、ここまで。

私はテーブルを持っています:tag_tasks

tag_idこれは、重要な 2 つの列を持つ結合テーブルです。task_id

両方のタグを持つタスクの数を取得したいと思います。

例: 私は atask(id = 12)と atag(id = 24と別のものを持っていますtag(id = 30)

tag_tasks には、次のレコードがあります。

tag_id  task_id
24      12
30      12

それを現実的にするためにそこにいくつかの記録もあるとしましょう:

tag_id  task_id
24      12
30      12
36      43
24      45
56      98
24      115
30      115

task_id に両方のターゲット タグが関連付けられている場合にのみ、レコードを返したいと思います。この場合、最初の 2 行 (task_id = 12) と最後の 2 行 (task_id = 115) だけで、合計カウントを取得します (この場合、私の最終目標は数字の 4 を返すことです)。

編集 - 結果セット

tag_id  task_id
    24      12
    30      12
    24      115
    30      115

しかし、最終的には次のような結果になりたいと思います(上記の結果の合計):

task_count_for_both_tags_combined
4

これについて考えるのは少し混乱するので、質問を明確にすることができるかどうか教えてください。

ありがとうございました。

編集 -これまでの私の結果 このコードは私を近づけますが、結果の数値を追加する必要があります-*これは現在のデータセットを突き出していることに注意してください。

SELECT COUNT( task_id ) AS task_count, tag_id
FROM  `tag_tasks` 
WHERE tag_id
IN ( 15, 11 ) 
GROUP BY task_id
HAVING task_count >1

これにより、次の結果が得られます。これには、次の合計が必要です。

task_count  task_id 
2           34
2           45

編集 - SQLFIDDLE の例 これが存在することを知ったばかりなので、わずかに大きなデータ セットを持つポスターの 1 つからの誤ったフィドルの回答を次に示します。このSQLは、私が望むものとは異なるタグを持つレコードを選択することになります(24と30だけではなく、31と32)。

http://www.sqlfiddle.com/#!2/116f9/1/0

4

7 に答える 7

1
select count(distinct(t1.task_id))-1 
from tag_tasks t1, tag_tasks t2 
where t1.task_id = t2.task_id 
    and t1.tag_id = t2.tag_id

このフィドルのように。ご不明な点がございましたら、コメントを残してください。

于 2013-07-09T16:26:57.460 に答える
1

OK、あなたが望むのは、この xref テーブルによって、関心のあるすべてのタグに関連付けられているタスク レコードを表示することだと思います。したがって、具体的には、タグとタスクの相互参照レコードを結び付けているすべてのタスクが必要です。タグ 24 とタグ 30 の両方にタスクを送信します。

これはおそらく、Task と Tag-Task の間の両方で 2 つの内部結合を使用して行うのが最適です。

SELECT t.taskId --or COUNT(*)
FROM Task t
INNER JOIN TagTasks tt1
   ON tt1.taskId = t.taskId
   AND tt1.tagId = 24
INNER JOIN TagTasks tt2
   ON tt2.taskId = t.taskId
   AND tt2.tagId = 30

結果:

12
115

...質問で定義されているとおりの正確な結果セットが必要な場合は、選択を変更して3番目の結合を追加します。

SELECT tt3.tagId, t.taskId
FROM Task t
INNER JOIN TagTasks tt1
   ON tt1.taskId = t.taskId
   AND tt1.tagId = 24
INNER JOIN TagTasks tt2
   ON tt2.taskId = t.taskId
   AND tt2.tagId = 30
INNER JOIN TagTasks tt3
   ON tt3.taskId = t.taskId
   AND (tt3.tagId = 24 OR tt3.tagId = 30)

結果:

tag_id  task_id
24      12
30      12
24      115
30      115

結合は、インデックス付きの列 (主キー フィールドなど) を使用する場合はコストがかからないため、この選択は Exists やその他のサブクエリよりも高速に実行されるはずです。すべての結合は内部結合であるため、その組み合わせの結果行が生成されるためには、すべての結合がフィルタおよび結合基準に一致する必要があります。各句は 1 つのタグ ID のみに一致するため、デカルト結合も生成しないでください。したがって、1 つの行でタグ 24 に一致する最初の結合と次のタグ 30 に一致する最初の結合に基づいて重複した結果が得られることはありません。

ただし、これはストアド プロシージャとして自動化する簡単なクエリではありません。検索するタグごとに Join が必要であり、さらに選択リストのフィールドを提供する Join が必要になるため、デカルトを生成せずに必要なことを実行するこの形式の単一のクエリをハードコーディングすることはほとんど不可能ですただし、繰り返し繰り返されるボイラープレート部分を持つこのクエリは、比較的簡単にアプリケーション コードで生成し、ネットワーク経由でサーバーに送信できます (ただし、エンド ユーザーが入力するものは常にインライン化しないでください)。

于 2013-07-09T16:31:50.513 に答える
1

http://www.sqlfiddle.com/#!2/116f9/3

きっと「レコードカウント」があなたの求める答えを教えてくれます!!

于 2013-07-09T16:50:07.567 に答える
1

これでうまくいくはずです。

SELECT *
FROM tableName a
WHERE exists( 
    select 1 
    from tableName b 
    where a.task_id = b.task_id
    and tag_id = 24)
AND exists( 
    select 1 
    from tableName b 
    where a.task_id = b.task_id
    and tag_id = 30)

SQL フィドル

実際のレコードではなくレコード数を返す場合は、に変更SELECT *SELECT COUNT(*)ます。または、この基準を満たす task_id の数だけが必要な場合は、SELECT COUNT(DISTINCT task_id)

于 2013-07-09T16:26:00.390 に答える
1

カウント部分では次のように機能しますか?

select 2*count(task_id) where task_id in (select task_id where tag_id=24) and task_id in (select task_id where tag_id=30)

基本的に、タスクに両方のタグがある場合、それをカウントに追加し、最後に 2 倍にします。where句は、他のデータを取得するための一般的な選択のために再利用できます。

于 2013-07-09T16:26:04.533 に答える
1

次のクエリを試してください:

SELECT A.*
FROM tag_tasks AS A
INNER JOIN 
(
SELECT TASK_ID , COUNT(*) AS CNT
FROM tag_tasks
WHERE TAG_ID = 24 OR TAG_ID = 30
GROUP BY TASK_ID
) AS B ON A.TASK_ID = B.TASK_ID
WHERE B.CNT = 2

SQLFIDDLE

結合クエリを使用しました。結合クエリは実行時に 1 回しか実行されませんが、EXIST 句と IN 句のクエリはテーブル内の各レコードに対して実行され、多くのデータがある場合は結果を生成するのに時間がかかるため、結合は EXIST 句と IN 句よりも優れたパフォーマンスを提供します。テーブル 。

于 2013-07-09T16:34:23.220 に答える
0

最後にTag_IDの追加フィルターを追加すると、編集のSQLfiddleが正常に機能するようですよね?

SELECT COUNT(*) 
FROM tableName a
WHERE exists( 
    select 1 
    from tableName b 
    where a.task_id = b.task_id
    and tag_id = 24)
AND exists( 
    select 1 
    from tableName b 
    where a.task_id = b.task_id
    and tag_id = 30)
AND (Tag_ID = 24 OR Tag_ID = 30) /* add this filter to exclude the IDs you don't want */
于 2013-07-09T19:43:14.440 に答える