結果をフラット化する> 正しいカウントを取得するために、クエリの
ファイルテーブルから他のテーブルへの1対多の関係があるとおっしゃいました
SQLにキーワードLOOKUP
しかない場合 JOIN
にすべてを詰め込む代わりに キーワードの場合、JOIN
を使用すると、テーブルAとテーブルBの関係が1対1であるかどうかを簡単に推測できます。 自動的に1対多を意味します。私は逸脱します。とにかく、私はあなたのファイルがdm_dataに対して1対多であることをすでに推測しているはずです。また、kc_dataに対するファイルも1対多です。 LEFT JOIN
最初のテーブルと2番目のテーブルの関係が1対多であることを示すもう1つのヒントです。ただし、これは決定的なものではありません。一部のコーダーは、すべてをLEFT JOIN
で記述するだけです。 。クエリのLEFTJOINに問題はありませんが、クエリに1対多のテーブルが複数ある場合は必ず失敗し、クエリは他の行に対して繰り返し行を生成します。
from
files
left join
dm_data ON dm_data.id = files.id
left join
kc_data ON kc_data.id = files.id
したがって、この知識を使用して、ファイルがdm_dataに対して1対多であり、kc_dataに対しても1対多であることを示します。これらの結合をチェーンし、1つのモノリシッククエリにグループ化することに問題があると結論付けることができます。
3つのテーブル、つまりapp(files)、ios_app(dm_data)、android_app(kc_data)があり、これがたとえばiosのデータである場合の例:
test=# select * from ios_app order by app_code, date_released;
ios_app_id | app_code | date_released | price
------------+----------+---------------+--------
1 | AB | 2010-01-01 | 1.0000
3 | AB | 2010-01-03 | 3.0000
4 | AB | 2010-01-04 | 4.0000
2 | TR | 2010-01-02 | 2.0000
5 | TR | 2010-01-05 | 5.0000
(5 rows)
そしてこれはあなたのAndroidのデータです:
test=# select * from android_app order by app_code, date_released;
.android_app_id | app_code | date_released | price
----------------+----------+---------------+---------
1 | AB | 2010-01-06 | 6.0000
2 | AB | 2010-01-07 | 7.0000
7 | MK | 2010-01-07 | 7.0000
3 | TR | 2010-01-08 | 8.0000
4 | TR | 2010-01-09 | 9.0000
5 | TR | 2010-01-10 | 10.0000
6 | TR | 2010-01-11 | 11.0000
(7 rows)
このクエリを使用するだけの場合:
select x.app_code,
count(i.date_released) as ios_release_count,
count(a.date_released) as android_release_count
from app x
left join ios_app i on i.app_code = x.app_code
left join android_app a on a.app_code = x.app_code
group by x.app_code
order by x.app_code
代わりに出力が間違っています:
app_code | ios_release_count | android_release_count
----------+-------------------+-----------------------
AB | 6 | 6
MK | 0 | 1
PM | 0 | 0
TR | 8 | 8
(4 rows)
連鎖結合はデカルト積と考えることができるため、最初のテーブルに3行あり、2番目のテーブルに2行ある場合、出力は6になります
。
これが視覚化です。すべてのiOSABに対して2つのAndroidABが繰り返されていることを確認してください。 3つのiosABがあるので、COUNT(ios_app.date_released)を実行すると何がカウントされますか?それは6になります。 COUNT(android_app.date_released)
でも同じです 、これも6になります。同様に、すべてのiosTRに対して4つの繰り返しandroidTRがあり、iosには2つのTRがあるため、8のカウントが得られます。
.app_code | ios_release_date | android_release_date
----------+------------------+----------------------
AB | 2010-01-01 | 2010-01-06
AB | 2010-01-01 | 2010-01-07
AB | 2010-01-03 | 2010-01-06
AB | 2010-01-03 | 2010-01-07
AB | 2010-01-04 | 2010-01-06
AB | 2010-01-04 | 2010-01-07
MK | | 2010-01-07
PM | |
TR | 2010-01-02 | 2010-01-08
TR | 2010-01-02 | 2010-01-09
TR | 2010-01-02 | 2010-01-10
TR | 2010-01-02 | 2010-01-11
TR | 2010-01-05 | 2010-01-08
TR | 2010-01-05 | 2010-01-09
TR | 2010-01-05 | 2010-01-10
TR | 2010-01-05 | 2010-01-11
(16 rows)
したがって、他のテーブルやクエリに結合する前に、各結果をフラット化する必要があります。
データベースがCTEに対応している場合は、それを使用してください。非常にきちんとしていて、非常に自己文書化されています:
with ios_app_release_count_list as
(
select app_code, count(date_released) as ios_release_count
from ios_app
group by app_code
)
,android_release_count_list as
(
select app_code, count(date_released) as android_release_count
from android_app
group by app_code
)
select
x.app_code,
coalesce(i.ios_release_count,0) as ios_release_count,
coalesce(a.android_release_count,0) as android_release_count
from app x
left join ios_app_release_count_list i on i.app_code = x.app_code
left join android_release_count_list a on a.app_code = x.app_code
order by x.app_code;
一方、MySQLのようにデータベースにCTE機能がまだない場合は、代わりにこれを行う必要があります。
select x.app_code,
coalesce(i.ios_release_count,0) as ios_release_count,
coalesce(a.android_release_count,0) as android_release_count
from app x
left join
(
select app_code, count(date_released) as ios_release_count
from ios_app
group by app_code
) i on i.app_code = x.app_code
left join
(
select app_code, count(date_released) as android_release_count
from android_app
group by app_code
) a on a.app_code = x.app_code
order by x.app_code
そのクエリとCTEスタイルのクエリは正しい出力を表示します:
app_code | ios_release_count | android_release_count
----------+-------------------+-----------------------
AB | 3 | 2
MK | 0 | 1
PM | 0 | 0
TR | 2 | 4
(4 rows)
ライブテスト
不正なクエリ: http://www.sqlfiddle.com/#!2/9774a/ 2
正しいクエリ: http://www.sqlfiddle.com/#!2/9774a/ 1