• ベストアンサー
  • すぐに回答を!

複数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を得られるのでしょうか? よろしくお願いします。

共感・応援の気持ちを伝えよう!

  • 回答数2
  • 閲覧数198
  • ありがとう数2

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

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

テーブル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ひとつひとつに対して結果を求めるのが自然だと思います。

共感・感謝の気持ちを伝えよう!

質問者からのお礼

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

関連するQ&A

  • 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を使用しています。

  • CASEの中にCASE

    CASE WHEN c1 IS NOT NULL THEN 'OK' ELSE (CASE WHEN c2 IS NOT NULL THEN 'OK' ELSE 'NO' ) END AS kekka; こういうようなCASEの中にCASEを使う方法はありますでしょうか?

  • 講座のある日を抽出したい

    以下にある二つのテーブル(coursemaster, opencourses)を結合して 月ごとに講義があるかをo,xで一覧にして[期待結果]の様な表を抽出したいです。 coursemaster テーブル course_id | course_name 1 | 経理講義 2 | 財務講義 3 |  簿記講義 4 | 税理講義 opencoursesテーブル   month course_id 200706 | 1      200706 | 3 200706 | 4 200707 | 4 200708 | 2 200708 | 4 [期待結果]      経理講義 財務講義  簿記講義  税理講義 200706  ○      ×     ○      ○ 200707  ×      ×     ×      ○ 200708  ×      ○     ×      ○ 以下の様なSQL文で表を結合してみたのですが 日付の値が重複されてしまい、期待通りの結果になりません。 誰かご教授いただけないでしょうか? SELECT month AS 開講日 ,CASE WHEN course_name='経理講義' THEN '○' ELSE '×' END AS 経理講義 ,CASE WHEN course_name='財務講義' THEN '○' ELSE '×' END AS 財務講義 ,CASE WHEN course_name='簿記講義' THEN '○' ELSE '×' END AS 簿記講義 ,CASE WHEN course_name='税理講義' THEN '○' ELSE '×' END AS 税理講義 FROM OpenCourses AS OC INNER JOIN CourseMaster AS CM ON OC.course_id = CM.course_id ORDER BY 1 ;

その他の回答 (1)

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

たぶんこんな感じを期待しているのだとおもうけど かならず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

共感・感謝の気持ちを伝えよう!

質問者からのお礼

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

関連する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 ;

  • グループ化データの割り算について

    SQLSERVER 言語 VB VS2008 いつも勉強させていただいています。 SQL文で 「0 除算エラーが発生しました。」 が出て、困っています。 アドバイスお願いいたします。 SQL文 COUNT(CASE WHEN CONVERT(CHAR(10), 納期, 111) = GETDATE() _ AND 入荷数 = 0 THEN 0 ELSE NULL END) _ / _ COUNT(CASE WHEN CONVERT(char(10), 納期, 111) = GETDATE() _ THEN 0 ELSE NULL END) * 100 AS '遅延率(%)' ・・・GROUP化 わかりずらいのですが、期間内の入荷数/全体数で割っています。 COUNTでも駄目でした。 個々のデータは取得できます。下記 COUNT(CASE WHEN CONVERT(CHAR(10), 納期, 111) = GETDATE() _ AND 入荷数 = 0 THEN 0 ELSE NULL END) AS 未入荷計 何か良い方法が御座いましたらご指導くださいませ。 よろしくお願いします。

  • CASE文について

    <環境> SQLSERVER2005 ACCESS2007 CASE文について質問です。 クエリで下記のSQL文を実行すると、「Case 式は、10 レベルまでしか入れ子にできません。」 とエラーになります。 このような場合、どのように記述すれば解決できるでしょうか? ご教授お願いします。 SELECT CASE WHEN (WA.MM = '01') THEN ROUND(SUM(WB.MONEY1), -3, 0) ELSE CASE WHEN (WA.MM = '02') THEN ROUND(SUM(WB.MONEY2), -3, 0) ELSE CASE WHEN (WA.MM = '03') THEN ROUND(SUM(WB.MONEY3), -3, 0) ELSE CASE WHEN (WA.MM = '04') THEN ROUND(SUM(WB.MONEY4), -3, 0) ELSE CASE WHEN (WA.MM = '05') THEN ROUND(SUM(WB.MONEY5), -3, 0) ELSE CASE WHEN (WA.MM = '06') THEN ROUND(SUM(WB.MONEY6), -3, 0) ELSE CASE WHEN (WA.MM = '07') THEN ROUND(SUM(WB.MONEY7), -3, 0) ELSE CASE WHEN (WA.MM = '08') THEN ROUND(SUM(WB.MONEY8), -3, 0) ELSE CASE WHEN (WA.MM = '09') THEN ROUND(SUM(WB.MONEY9), -3, 0) ELSE CASE WHEN (WA.MM = '10') THEN ROUND(SUM(WB.MONEY10), -3, 0) ELSE CASE WHEN (WA.MM = '11') THEN ROUND(SUM(WB.MONEY11), -3, 0) ELSE CASE WHEN (WA.MM = '12') THEN ROUND(SUM(WB.MONEY12), -3, 0) END END AS MONEY FROM (WA INNER JOIN WB ON (WA.YYYY = WB.YYYY)) INNER JOIN WC ON (WA.YYYY = WC.YYYY)

  • 複数テーブルの集計その2

    お世話になります。 先日テーブルの集計について教えていただき、下記集計結果を取得することができたのですが、 新たに自由形50~平泳ぎ50までの合計を追加したいのです。(一人で4種目参加する場合は4と数える) テーブル1 AreaID   AreaName --------------------- 1 北海道 2 東北 テーブル3 ID AreaID   Name  Item1   Item2  Item3 Item4 --------------------------------------------------------- 1   2    鈴木    2    1    4     3 2   1    田中    1    2    null   null 3   2    伊藤    3    null   2    4  「集計結果」       参加人数 自由形50 自由形100 背泳ぎ50 平泳ぎ50  追加部分 --------------------------------------------------------------- 北海道     1     1       1      0      0       2 東北      2     1       2      2      2       7   $sql="select AreaName, count(distinct ID) 参加人数, count(case when Item=1 then 1 else null end) as 自由形50, ・・・略 from t1 as x left join (select ID,AreaID,1 as Item from t3 where Item1=1 or Item2=1 or Item3=1 or Item4=1 union all select ID,AreaID,2 as Item from t3 where Item1=2 or Item2=2 or Item3=2 or Item4=2 ) as y on x.AreaID=y.AreaID group by AreaName order by x.AreaID というようにおしえていただきました。 null以外を取得するSQLをカウントとselectに追加すればいいのかと思い試したのですが期待した値を取得できません。 count(case when Item=AAA then 1 else null end) as abc,と union all select ID,AreaID,AAA as Item from テーブル3 where ItemID1<>'' or ItemID2<>'' or ItemID3<>'' or ItemID4<>'' or (ItemID1<>'' and ItemID2<>'') ・・・ バージョンはMySQL4.1.18です。 よろしくお願い致します。

    • ベストアンサー
    • MySQL
  • 複数レコードのデータを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 実は別サイトでも投稿しておりますが回答がなく大変困っております。 どうか宜しくお願い致します。

  • MySQLでWHEN句のサブクエリ中にて

    MySQL ver.5.0.95です。 PHPからSQL文を作ってDBへインサートしているのですが 重複した値が合った場合はupdateするように書いています。 TBL1には |id   |string   |count 1    aaa    0 2    bbb    3 3    ccc    1 TBL2には |id2    |string2    |count2 1      aaa      0 2      bbb      2 3      ccc      1 実際はもう少し複雑ですが、こういう感じでデータが入ってるとします。 このとき、TBL1のそれぞれをインサート若しくはアップデートするのに TBL2の同一IDのものの、count2の状態によって場合分けしたく 同一IDのcount2が1以上なら変更しない、という風にするため以下のように書いたのですが insert into TBL1 values (1, "aaa", 3), (2, "bbb", 3), (3, "ccc", 3), (4, "ddd", 3) on duplicate key update count = CASE WHEN (select count2 from TBL2 where id2 = values(id)) >=1 THEN count ELSE count + values(count) END; #1064 - You have an error in your SQL syntax;というエラーになって出来ません。 WHENの中のサブクエリで、where id2 = values(id) 恐らくこの文がダメなようです。 例えば決め撃ちで1つ1つ書くと通ります。 insert into TBL1 values(1, "aaa", 3) on duplicate key update count = CASE WHEN (select count2 from TBL2 where id2 = 1) >=1 THEN count ELSE count + values(count) END; insert into TBL1 values(2, "bbb", 3) on duplicate key update count = CASE WHEN (select count2 from TBL2 where id2 = 2) >=1 THEN count ELSE count + values(count) END; insert into TBL1 values(3, "ccc", 3) on duplicate key update count = CASE WHEN (select count2 from TBL2 where id2 = 3) >=1 THEN count ELSE count + values(count) END; insert into TBL1 values(4, "ddd", 3) on duplicate key update count = CASE WHEN (select count2 from TBL2 where id2 = 4) >=1 THEN count ELSE count + values(count) END; これをエラーになったような文に変えて1文にまとめたいのですが、無理でしょうか? あとそもそもこれをまとめたほうが速いと思ってそうしたいのですが、 変わらないのなら1文1文;でつなげて書くやり方でいこうと思っています。 まとめると速くなることはあるでしょうか?

    • ベストアンサー
    • MySQL
  • フィールドのデータ型を取得して判断したい

    syscolumns から 各フィールドごとのデータ型を取得して「数字」項目か「文字」項目か判断させたいのです。 要は Where句で使うパラメータにフィールドが「文字」項目であれば自動的に「'」を付与するようにしたいのです。 下記のSelect文でscaleがNULLにも関わらずタイプに「文字」と入りません、どうしてでしょうか ---------------------------------------------------------------- select sc.name as フィールド名,sc.scale,case sc.scale when null then '文字' else '数字' end as タイプ from マスター管理_DB.dbo.sysobjects as so join マスター管理_DB.dbo.syscolumns as sc on so.id=sc.id join マスター管理_DB.dbo.systypes as st on sc.xtype=st.xtype where so.type='V' and left(so.name,2)='K_' and LEFT(st.name,3)<>'sys' ---------------------------------------------------------------- (フィールド名)  (scale)  (タイプ) 勘定科目コード   0     数字 勘定科目名    NULL   数字(←「文字」になってほしい) 貸借         NULL   数字(←「文字」になってほしい) 計科目名      NULL   数字(←「文字」になってほしい) ---------------------------------------------------------------- また、日付(日時)を判断できる項目はないでしょうか? よろしくお願いします。

  • 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 ON の SQLの実行が遅いです

    下記のようなSQLを実行しています。 SELECT db_1.*, CASE WHEN db_1.tihou = '北海道' THEN '1' WHEN db_1.tihou = '青森' THEN '2' WHEN db_1.tihou = '秋田' THEN '3' WHEN db_1.tihou = '山形' THEN '4' WHEN db_1.tihou = '岩手' THEN '5' WHEN db_1.tihou = '宮城' THEN '6' WHEN db_1.tihou = '福島' THEN '7' else '9' END AS kita, db_2.no, db_2.title, db_3.name, db_3.url from (db_1 left JOIN db_2 ON db_1.nonber = db_2.no) LEFT join db_3 on db_1.nonber = db_3.non WHERE db_1.nonber LIKE '1%' ORDER BY db_1.day DESC LIMIT 0,30 ※DB名、テーブル名は仮名としています db_1というメインのデータベースに合わせて db_2、db_3の情報をくっつけて結果を出したいと思っていますが実行に25秒強かかっています。 (PHPMyadmilで実行しました) db_1単体でしたら実行は速かったのですが db_2、db_3はどうしても付属させたく、また、db_1とは別のデータとしておきたいと考えています。 補足ではありますが、 「db_1.*」としているのは、db_1のデータ全て表示に使う為です。 良い方法をご存知の方いらっしゃいましたら、どうかお教え下さい。

    • ベストアンサー
    • MySQL
  • 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 よろしくお願いします