次のクエリがあります。
SELECT
COUNT(*) AS `count`
FROM
agreements
WHERE
start_date >= STR_TO_DATE('14-01-2015','%d-%m-%Y')
AND
start_date < STR_TO_DATE('15-01-2015','%d-%m-%Y')
AND
active = 1
AND
(driv_id, veh_id) NOT IN (
SELECT
a.driv_id, a.veh_id
FROM
agreements a
INNER JOIN
types t
ON
a.agreement_type_id = t.id
WHERE
DATE_ADD(a.start_date,INTERVAL t.initial_term YEAR) <
DATE_SUB(STR_TO_DATE('14-01-2015','%d-%m-%Y'),INTERVAL 2 MONTH)
)
次に、同じクエリを実行する必要がありますが、1つの変更を加えて、NOT
句の(driv_id, veh_id) NOT IN ...
部分からWHERE
を削除します。
これは明らかに良くありません。なぜなら、DRYに違反する1つの単語を除いたクエリを文字通りコピーして貼り付けるからです。
グーグルで検索してWITH
コマンドを見つけましたが、MySQL5.1.73では使用できません。 WITH
を使用して実行したクエリは次のとおりです。
WITH tuples AS
(
SELECT
a.driv_id, a.veh_id
FROM
agreements a
INNER JOIN
types t
ON
a.agreement_type_id = t.id
WHERE
DATE_ADD(a.start_date,INTERVAL t.initial_term YEAR) <
DATE_SUB(STR_TO_DATE('14-01-2015','%d-%m-%Y'),INTERVAL 2 MONTH)
)
SELECT
SUM(IF((a.driv_id, a.veh_id) IN `tuples`, 1, 0)) as in_sum
SUM(IF((a.driv_id, a.veh_id) NOT IN `tuples`, 1, 0)) as not_in_sum
FROM
agreements
WHERE
start_date >= STR_TO_DATE('14-01-2015','%d-%m-%Y')
AND
start_date < STR_TO_DATE('15-01-2015','%d-%m-%Y')
AND
active = 1
サブクエリの結果をtuples
という一時テーブルに保存し、(メインクエリで)次を選択して、一時テーブルでもこれを実行してみました。
SUM(IF((a.driv_id, a.veh_id) IN tuples, 1, 0)) as in_sum
SUM(IF((a.driv_id, a.veh_id) NOT IN tuples, 1, 0)) as not_in_sum
しかし、これは構文エラーをスローします(理由はよくわかりません)。
おそらく結合を使用してこれを行う方法はありますか(結合クエリを実行しようとしましたが、ブレークスルーはありませんでした)?
はい。外部結合を使用してクエリを書き換えることで、サブクエリを繰り返さずに両方の結果を返すことができます。以下は、お使いのバージョンと同じ結果を返します。
_SELECT
COUNT(*) AS `count`
FROM
agreements AS ag
LEFT JOIN
(
SELECT
a.driv_id, a.veh_id
FROM
agreements a
INNER JOIN
types t
ON
a.agreement_type_id = t.id
WHERE
DATE_ADD(a.start_date,INTERVAL t.initial_term YEAR) < DATE_SUB(STR_TO_DATE('14-01-2015','%d-%m-%Y'),INTERVAL 2 MONTH)
) AS s ON ag.driv_id = s.driv_id AND ag.veh_id = s.veh_id
WHERE
ag.start_date >= STR_TO_DATE('14-01-2015','%d-%m-%Y')
AND
ag.start_date < STR_TO_DATE('15-01-2015','%d-%m-%Y')
AND
ag.active = 1
AND
s.driv_id IS NULL
;
_
それは事実上あなたの_not_in_sum
_になります。両方のカウントを一度に返すには、where句からNULLチェックを削除し、次のようにSELECT
でCOUNT(s.driv_id)
を使用します。
_SELECT
COUNT(s.driv_id) AS in_sum,
COUNT(*) - COUNT(s.driv_id) AS not_in_sum
FROM
...
_
サブクエリが重複を返す可能性がある場合は、それにDISTINCT
を追加します。そうしないと、_in_sum
_が誤った結果を返す可能性があります。
WITH
句については、まだ正式にリリースされていないバージョン5.7のマニュアルにも記載されていませんが、一時テーブルを使用してエミュレートすることはおそらく理にかなっています。そのメソッドを試しているときに発生したエラーは、試行したIN
/_NOT IN
_の右側が単なるテーブル名であったのに対し、サブクエリである必要があったためです。
_(a.driv_id, a.veh_id) IN (SELECT driv_id, veh_id FROM tuples)
_