複数JOINしているとCOUNTが正しく取得できない!SQLのCOUNTの使い方について教えてください

このQ&Aのポイント
  • LAMP環境で開発をしており、SQL文でCOUNTを求める際に問題が発生しています。
  • 複数のJOINを使用して結果をまとめて取得しようとすると、期待した結果が得られません。
  • 正しい結果を得るためには、COUNTの使い方に注意する必要があります。
回答を見る
  • ベストアンサー

複数JOINしているとCOUNTが正しく取得できな

LAMP環境で開発をしています。 SQL文でCOUNTを求める際に、まとめて結果を求めようとして上手く行きません。 状況としては以下です。 テーブルdはidをkeyにa,b,c3つのテーブルとjoinしています。 id = 1の場合、テーブルa,b,cにマッチするレコードがそれぞれに4個、1個、0個あります。 ひとつひとつを SELECT COUNT(CASE WHEN a.name IS null THEN 1 ELSE null END) as a_count FROM d INNER JOIN a ON a.id = d.id WHERE d.id = 1 として結果を求めると4,1,0と出るのですが、まとめて SELECT COUNT(CASE WHEN a.name IS null THEN 1 ELSE null END) as a_count, COUNT(CASE WHEN b.name IS null THEN 1 ELSE null END) as b_count, COUNT(CASE WHEN c.name IS null THEN 1 ELSE null END) as c_count FROM d INNER JOIN a ON a.id = d.id INNER JOIN b ON b.id = d.id INNER JOIN c ON c.id = d.id WHERE d.id = 1 とすると28,5,0という値が返されます。 どのように書けば正しい4,1,0を得られるのでしょうか? よろしくお願いします。

  • MySQL
  • 回答数2
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
  • jjon-com
  • ベストアンサー率61% (1599/2592)
回答No.1

テーブルa内にid=1の行は5行存在。うち4行はnameがnullで,1行はname登録済。 テーブルb内にid=1の行は7行存在。うち1行はnameがnullで,6行はname登録済。 テーブルc内にid=1の行は1行存在。その1行はname登録済で,nameがnullは無し。 これを次のSQL文で結合すれば, 出力される行数は 5×7×1=35行分。 SELECT * FROM d INNER JOIN a ON a.id = d.id INNER JOIN b ON b.id = d.id INNER JOIN c ON c.id = d.id WHERE d.id = 1 そのうち, a.nameがnullなのは(4)×7×1=28行分, b.nameがnullなのは5×(1)×1= 5行分, c.nameがnullなのは5×7×(0)= 0行分。 > どのように書けば正しい4,1,0を得られるのでしょうか? 無意味にテーブルa,b,cを結合していること自体が正しくないわけですから, テーブルa,b,cひとつひとつに対して結果を求めるのが自然だと思います。

bacchus047
質問者

お礼

ご明察です。 楽しようとすると逆にこういうことになってしまいますね。 ありがとうございました。

その他の回答 (1)

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.2

たぶんこんな感じを期待しているのだとおもうけど かならずnameがユニークだとは限らないためnameで判断するのは微妙 SELECT count(DISTINCT a.name) as a_count ,count(DISTINCT b.name) as b_count ,count(DISTINCT c.name) as c_count FROM d LEFT JOIN a ON a.id = d.id LEFT JOIN b ON b.id = d.id LEFT JOIN c ON c.id = d.id WHERE d.id = 1

bacchus047
質問者

お礼

参考にさせて頂きました。 ありがとうございました。

関連するQ&A

  • SELECT実行結果のレスポンス改善について

    いつもお世話になっております。 Oracle9i+XP(CPU=PentiumCore2Duo,メモリ=2MB)の環境にて、以下のようなSELECT文なのですが、実行結果が出るまでに約45分もかかってしまいます。 何が悪いのか切り分けるために、以下の副問い合わせのみを切り取ってSQLPLUSで実行してみると15件ずつが約10秒おきに返ってくるという現象が確認できたため、おそらくこの副問い合わせではないかと思っております。 データ件数としては、ZAIテーブルが約6万件、MEISAIテーブルが約12万件、VIEW_ROOM_CALENDERビューが約6千件で、それ以外はしれとります。 一応すべてのテーブルのキーにはインデックスがはられているようです。 色々と調べてautotraceにて実行計画などを見てみましたが正直よくわかりませんでした。 テーブル構造やリレーション、カラム数、レコード長など情報が少なく大変申し訳ないのですが必要であれば提示させていただきますので、SQL文がおかしいとか、ネック部分の調べ方とか、なにかヒントのようなものでも結構ですので、どなたかご教授いただけませんでしょうか? 宜しくお願い致します。 select D.KANJYA_NO || ',' || D.NAME || ',' || A.BYOU_NAME || ',' || count(COL_PT) || ',' || count(COL_OT) || ',' || count(COL_ST) from ( -- 副問い合わせ select B.KANJYA_NO as KAN_NO, B.KAIKEI_DATE, G.BYOUTOU_NAME as BYOU_NAME, (case when C.MASTER_CODE in ('01017' , '01022' , '01025') then B.TOTAL_KAISUU else NULL end) as COL_PT, (case when C.MASTER_CODE in ('01019' , '01021' , '01023') then B.TOTAL_KAISUU else NULL end) as COL_OT, (case when C.MASTER_CODE in ('01016' , '01020' , '01024') then B.TOTAL_KAISUU else NULL end) as COL_ST from ZAI&1 B inner join MEISAI&1 C on C.NYUUGAI = B.NYUUGAI and C.KANJYA_NO = B.KANJYA_NO and C.ZAI_NO = B.ZAI_NO and C.KAIKEI_DATE = B.KAIKEI_DATE and B.KAIKEI_DATE Like '&1' || '%' and B.NYUUGAI = 2 and B.KANJYA_NO not like '*%' and C.MASTER_CODE in ('01017','01022','01025','01019','01021','01023','01016','01020','01024') inner join NYUUIN_ROOM E on C.KANJYA_NO = E.KANJYA_NO inner join VIEW_ROOM_CALENDER H on E.KANJYA_NO = H.KANJYA_NO and C.KAIKEI_DATE = H.YYYYMMDD and lpad(E.ROOM_NO,'10','0') = TO_NUMBER(H.ROOM_NO) inner join ROOM_TABLE F on E.ROOM_CODE = F.ROOM_CODE inner join BYT_TABLE G on G.BYOUTOU_CODE = F.BYOUTOU_CODE ) A inner join KANJYA D on A.KAN_NO = D.KANJYA_NO group by D.KANJYA_NO, D.NAME, D.BIRTH, A.BYOUTOU_NAME ;

  • joinの入れ子について

    A(contenthead)をベースにAがBに存在せずかつCに存在しないデータをを作りたいのですが上手く行きません。以下を実行すると SELECT a.contentid, b.contentid, d.contentid From (contenthead as a LEFT JOIN group as b on a.contentid = b.contentid) left join (contenthead as c LEFT JOIN ouser as d on c.contentid = d.contentid) on a.contentid = c.contentid 表示結果は 1、1、NULL 2、NULL、Null 3、NULL、3 4、NUL、4 と出て来ます。従って両方にないのは2だけということになります。 実際のデータもそうなっています。 そこで、 WHERE ((b. contentid) is null) and ((d. contentid) is null)を上記SQLに付加するとなぜか 2、NULL、Null 3、NULL、null 4、NUL、NULL と表示されます。 教えて頂きたいことお分かり戴けますでしょうか宜しく御願い致します。

    • ベストアンサー
    • MySQL
  • JOIN句への変換

    はじめまして。 「*=」をJoin句に直したいのですが、同様の結果がえられません(T.T) SQL初心者です、どうぞよろしくお願いいたします。 この式をJOIN句に直したいです。 FROM A_TBL, B_TBL as B_TBL01, B_TBL as B_TBL02, C_TBL, D_TBL WHERE A_TBL.No = B_TBL01.No AND A_TBL.No = B_TBL02.No AND A_TBL.No = C_TBL.No AND A_TBL.No *= D_TBL.No AND C_TBL.ID *= D_TBL.ID AND ↓こうしたのですが、正しい結果がえられません。 FROM (D_TBL RIGHT OUTER JOIN C_TBL ON C_TBL.ID = D_TBL.ID) RIGHT OUTER JOIN A_TBL INNER JOIN B_TBL AS B_TBL01 ON A_TBL.No = B_TBL01.No1.No INNER JOIN B_TBL AS B_TBL02 ON A_TBL.No = B_TBL02.No2.No ON A_TBL.No = D_TBL.No AND A_TBL.No = C_TBL.No どうぞ、ご教授お願いいたします。

  • count0の取り方

    2つのテーブルを結合しある項目の集計を取りたいと思ってるのですが数が0の場合の表示がされません 0を表示させる方法がわかるかたどうぞよろしくお願いします テーブル1 id | cd ---+-------- 1 | 1000 2 | 2000 3 | 3000 4 | 4000 テーブル2 id | cd ---+-------- 1 | 1000 2 | 2000 3 | 2000 4 | 4000 5 | 4000 出したい結果 cd | count -----+-------- 1000 | 1 2000 | 2 3000 | 0   ←現状では0がでません 4000 | 2 考えたSQL SELECT t1.cd,CASE THEN count(t2.cd) = NULL THEN 0 ELSE count(*) END FROM t1 LEFT OUNTER JOIN t2 ON t1.cd = t2.cd GROUP BY t1.cd ORDER BY t1.cd よろしくお願いします

  • 複数レコードのデータを1レコードに集約したい

    お世話になります。 複数レコードのデータを1レコードに集約したいのですが色々試してみましたが上手くいきません。 まず、以下のようなテーブルがあります。 TableA(キーはID) ID NO 1, 2 TableB(キーはIDとNO) ID NO SYU_NO FUKU_NO 1, 1, 1, 1 1, 2, 1, 2 1, 3, 2, 1 2, 1, 1, null    ・    ・ TableC(キーはIDとKUBUNとNO) ID KUBUN(SYU or FUKU) NO START END KAKUNIN 1, 1, 1, 20090101, 20091231, 20090310 1, 1, 2, 20090201, 20091130, 20090310 1, 2, 1, 20090401, 20100331, 20090312    ・    ・ これを、以下のようなレコードにしたいのですが・・。 ID START(SYU_NO) END(FUKU_NO) START(FUKU_NO) END(FUKU_NO) 1, 20090101, 20091231, 20090401, 20100331 以下のようなselect文を作成しましたが・・。 select A.ID || ',' || case when C.KUBUN = 1 then C.START end || ',' || case when C.KUBUN = 1 then C.END end || ',' || case when (C.KUBUN = 2 and B.FUKU_NO = C.NO) then C.START end || ',' || case when (C.KUBUN = 2 and B.FUKU_NO = C.NO) then C.END end || ',' || from TableA A inner join TableB B on A.ID = B.ID and A.NO = B.NO inner join TableC C on B.ID = C.ID and ((C.KUBUN = 1 and B.SYU_NO = C.NO) or (C.KUBUN = 2 and B.FUKU_NO = C.NO)) ; 以下のような結果が返ってきます。 ID START(SYU_NO) END(FUKU_NO) START(FUKU_NO) END(FUKU_NO) 1, 20090101, 20091231, , 1, , , 20090401, 20100331 実は別サイトでも投稿しておりますが回答がなく大変困っております。 どうか宜しくお願い致します。

  • caseを使った条件分岐の加算がうまくいかない

    SQLで条件によって加算するか、しないかを判定したいと思っています。 ■テーブル:test name,flag,number mike,4,1 mike,4,2 mike,5,3 mike,6,4 mike,7,5 mike,8,6 mike,9,7 ■書いたSQL SELECT test.name AS "name", (CASE WHEN flag = '4' THEN sum(number) ELSE NULL END) AS "4", (CASE WHEN flag = '5' THEN sum(number) ELSE NULL END) AS "5", (CASE WHEN flag = '6' THEN sum(number) ELSE NULL END) AS "6", (CASE WHEN flag = '7' THEN sum(number) ELSE NULL END) AS "7", (CASE WHEN flag = '8' THEN sum(number) ELSE NULL END) AS "8", (CASE WHEN flag = '9' THEN sum(number) ELSE NULL END) AS "9" FROM test GROUP BY test.name ■結果 4,5,6,7,8,9 null,null,null,null,null,28 欲しい結果は、フラグが4ののものの合計。flagが「4」の場合は、「3」という結果が返ってきてもらいたいです。 flagが5の場合は、3が返ってきてもらいたいです。 SQLが間違っているのですが、どこが間違っているのかわかりません。どのように修正すればよろしいでしょうか?よろしくお願いします。 環境はSQLiteを使用しています。

  • JOINで複数の表をまとめる場合の書き方

    質問させてください。 SQLのJOINで複数の表をまとめる場合、以下のどちらの方法が一般的でしょうか。 A, B, C : 表 X, Y : 条件 表ごとにくぎる (A INNER JOIN B ON X) INNER JOIN C ON Y 条件ごとにくぎる A INNER JOIN B INNER JOIN C ON Y ON X 以上よろしくお願いいたします。

  • サブクエリを使用せずにLEFT JOIN + GROUP BY + ORDER BYでデータの取得

    課題テーブル: 1 課題1 Aさん 2 課題1 Bさん 3 課題1 Cさん 4 課題1 Dさん 5 課題1 Eさん 6 課題2 Bさん 7 課題2 Cさん 成績テーブル: Aさん 算数 1 Aさん 国語 2 Bさん 算数 3 Cさん 算数 2 Dさん 国語 1 目的: 課題1を算数の成績順に取得したい。 普通にLEFT JOINすると以下のようになる。 1 課題1 Aさん 算数 1 1 課題1 Aさん 国語 2 2 課題1 Bさん 算数 3 3 課題1 Cさん 算数 2 4 課題1 Dさん 国語 1 5 課題1 Eさん NULL NULL ここから名前を1つにまとめて、成績順に。 1 課題1 Aさん 算数 1 3 課題1 Cさん 算数 2 2 課題1 Bさん 算数 3 4 課題1 Dさん NULL NULL 5 課題1 Eさん NULL NULL このようにしたいのですが、名前でGROUP BYすると科目と成績の整合性がとれなくなってしまい、正しく順位づけできません。 ORDER BY CASE  WHEN 成績.科目 = '算数' THEN '0'  WHEN 成績.科目 IS NULL THEN '2'  ELSE '1' END, 成績.科目, 成績.成績 サブクエリを使わずに実行する方法は、何かないものでしょうか。

    • ベストアンサー
    • MySQL
  • テーブルを結合

    テーブルの結合に関して質問します。 ネットなどでinner joinを使った複数のテーブル結合が参考として 書いてあったのですが(3つまで), 4つテーブルを結合する事は 出来るのでしょうか? A,B,CテーブルにはID,NAMEがあります。 DテーブルにはA,B,CテーブルのIDがあります。 参考サイトを見て3つのテーブルを結合するSQLが以下になります。 SELECT a.name, b.name, c.name FROM a INNER JOIN (b INNER JOIN c ON b.id = c.id) ON a.id = c.id よろしければアドバイスお願いします。

  • JOINでの結果取得 サブクエリをJOINする

    WordPressのデータベースでテーブル2つを結合して以下の情報を取得しようとしています メール(wp_users.user_email)|名前(wp_usermeta.meta_value)|登録日時(wp_users.user_registered ) 123@a.com,山田,2012-06-17 12:33:44 456@b.jp,田中,2012-06-21 07:26:54 789@c.ne.jp,\N,2009-08-11 12:19:00 1234@d.ne.jp,\N,2009-08-11 12:19:00 321@x.ne.jp,\N,2009-08-11 12:19:00 ・ユーザーはwp_usersテーブルにeメール情報(user_email)を必ず持ている ・ユーザーの名前はwp_usermetaテーブルのwp_usermeta.meta_keyがuser_nameなレコードに保存されているが、ユーザーによってあるものとないものがある。無い場合はNULLにする。 テーブル構造は添付した画像に記載されています。 ■ユーザ数 mysql> SELECT COUNT(*) FROM wp_users; 18290 まずwp_usersとwp_usermetaをLEFT JOINしてmeta_key = 'user_name'なレコードを取得しようとしましたが、user_nameを持っているユーザーのみしか取得できませんでした。 ■user_nameを持っていないユーザーが取得できない SELECT u.user_email, m.meta_value FROM wp_users AS u LEFT JOIN wp_usermeta AS m ON u.ID = m.user_id WHERE m.meta_key = 'user_name'\G 2075 rows in set (0.00 sec) 次にサブクエリをJOINしました。結果は正しいものを取得できたのですが、実行時間が40秒以上かかってしまい実用性がありません。 ■欲しい結果(速度が遅い) SELECT u.user_email, a.meta_key, a.meta_value, u.user_registered FROM wp_users AS u LEFT JOIN (select * from wp_usermeta where meta_key = 'user_name') as a ON u.ID = a.user_id; 18290 rows in set (45.45 sec) この結果を取得できる、正しいSQLを教えてください。よろしくお願いします。

    • ベストアンサー
    • MySQL