• ベストアンサー
  • 困ってます

SQLの書き方

以下の条件を取得したいのですがどのようなSQLを組めばいいか悩んでます。 テーブルA(列はC1,C2,C3,C4 PKはC1,C2です。) ■テーブルAのデータ C1  C2   C3   C4 1   1   50   備考1です。 1   2   75   備考2です。 2   1   25   備考3です。 3   1   75   備考4です。 3   2   90   備考5です。 3   3   50   備考6です。 ■取得したい結果 C1  C2   C3   C4 1   2   75   備考2です。 2   1   25   備考3です。 3   2   90   備考5です。 ■取得したい条件 C1でグルーピングしたなかでC3の値が一番大きな行を取得する。 現在は以下のようなSQLを書いています。 SELCT T1.* FROM テーブルA T1, (SELECT C1,MAX(C3) AS C3MAX FROM テーブルA GROUP BY C1) T2 WHERE T1.C1 = T2.C1 AND T1.C3 = T2.C3MAX もう少し簡単なSQLで出来そうですが、うまく思いつきません。 宜しくお願いします。

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

  • 回答数4
  • 閲覧数139
  • ありがとう数3

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

  • ベストアンサー
  • 回答No.4
  • 3rd_001
  • ベストアンサー率66% (115/174)

掲示板を勘違いしてOracleで作成していました。 create table a ( c1 int, c2 int, c3 int, c4 nvarchar(50) ); select x.C1,x.C2,x.C3,x.C4 from ( select C1,C2,C3,C4,max(C3) over(partition by C1) max_c3 from a) AS x where x.C3 = x.max_c3; SQL Serverだとこっち。

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

質問者からのお礼

ご回答ありがとうございます。 対象のテーブルが120万件以上あるのでパフォーマンスを考慮したSQLだととても助かります。 試してみたいと思います。

関連するQ&A

  • 副問い合わせについて

    お世話になります。明日から仕事で使うのですが、下記の構文が よく理解できません。宜しくお願い致します。 SQL Severは経験ありません。 経験はInfomixSql,Access,MySql程度です。 (1)行副問い合わせ(副問い合わせの結果が1行n列で返ってくる) SELECT * FROM t1 WHERE (c4, c2) = (SELECT MAX(c1), 'a' FROM t2); このwhere節の結合条件はどのような感じになるのでしょうか? (2)表副問い合わせ(副問い合わせの結果がm行n列(表)で返ってくる) SELECT * FROM t1 WHERE c4 IN ( SELECT c1 FROM t2 WHERE c4 >= 10 ) ORDER BY c1; 、 SELECT x1.c1, x2.y4 FROM t1 x1, ( SELECT c3, SUM(c4) AS y4 FROM t2 GROUP BY c3) AS x2 WHERE x1.c3 = x2.y4 ORDER BY c1; (1)に同じです。 参考になりそうなサイトでも結構ですので 宜しくお願い致します。

  • SQLの書き方

    select A.NO, A.NAME, count(B.TEN) FROM T1 A, T2 B GROUP BY A.NO ORDER BY 3 DESC 結果として以下のようになってほしいのですが、どのようにSQLを書けばよいのでしょうか? 結果 NO | NAME | TEN ---+------+----- 3 + 上村 + 40 1 + 吉田 + 11 2 + 浅野 + 6 T1テーブル NO | NAME ---+-------- 1 + 吉田 2 + 浅野 3 + 上村 T2テーブル NO | TEN ---+-------- 1 + 10 2 + 5 3 + 0 1 + 1 2 + 1 3 + 40

  • (初心者です)パフォーマンスの良いSQLの書き方

    SQL初心者です。初歩的かもしれませんが 教えていただけると助かります。 社員情報を管理するマスタテーブル『MST』(PKはSHAIN_ID)、 社員のシステムログイン履歴をログとして残すテーブル『LOG』 (PKはSEQのみ、SHAIN_IDとLOGIN_DATEを持つ) があります。 社員ごとに最新のログイン日付を表示するとき、 以下のようなSQLを書いたところ「パフォーマンス上あまりよくないSQL」 と言われてしまったのですが、どのように改善すればよいでしょうか? ------------------------------------------ SELECT MST.SHAIN_ID,     MST.SHAIN_NAME,     LOG.LOGINTIME FROM  MST,    (SELECT LOGINUSERID,        MAX(LOGINDATE) LOGINDATE     FROM LOG     GROUP BY SHIAN_ID    ) LOG WHERE MST.SHAIN_ID = LOG.SHAIN_ID ORDER BY    MST.SHAIN_ID ------------------------------------------

その他の回答 (3)

  • 回答No.3
  • 3rd_001
  • ベストアンサー率66% (115/174)

あえていうなら分析関数を使う。 テーブルAのFullスキャン2回を1回に減らせるからデータ量が多いと効果があるかもしれません。 create table a ( c1 number(2), c2 number(2), c3 number(2), c4 varchar2(50) ); insert into a values(1,1,50,'備考1です。'); insert into a values(1,2,75,'備考2です。'); insert into a values(2,1,25,'備考3です。'); insert into a values(3,1,75,'備考4です。'); insert into a values(3,2,90,'備考5です。'); insert into a values(3,3,50,'備考6です。'); select C1,C2,C3,C4 from ( select C1,C2,C3,C4,max(C3) over(partition by C1) max_c3 from a) where C3 = max_c3 C1 C2 C3 C4 ---------- ---------- ---------- ----------- 1 2 75 備考2です。 2 1 25 備考3です。 3 2 90 備考5です。 実行計画 ---------------------------------------------------------- Plan hash value: 2104940997 ---------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 6 | 474 | 4 (25)| 00:00:01 | |* 1 | VIEW | | 6 | 474 | 4 (25)| 00:00:01 | | 2 | WINDOW SORT | | 6 | 396 | 4 (25)| 00:00:01 | | 3 | TABLE ACCESS FULL| A | 6 | 396 | 3 (0)| 00:00:01 | ---------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("C3"="MAX_C3") Note ----- - dynamic sampling used for this statement 統計 ---------------------------------------------------------- 0 recursive calls 0 db block gets 7 consistent gets 0 physical reads 0 redo size 707 bytes sent via SQL*Net to client 420 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 1 sorts (memory) 0 sorts (disk) 3 rows processed select T1.* FROM A T1,(SELECT C1,MAX(C3) AS C3MAX FROM A GROUP BY C1) T2 WHERE T1.C1 = T2.C1 AND T1.C3 = T2.C3MAX; 実行計画 ---------------------------------------------------------- Plan hash value: 494933846 ----------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 92 | 8 (25)| 00:00:01 | |* 1 | HASH JOIN | | 1 | 92 | 8 (25)| 00:00:01 | | 2 | TABLE ACCESS FULL | A | 6 | 396 | 3 (0)| 00:00:01 | | 3 | VIEW | | 6 | 156 | 4 (25)| 00:00:01 | | 4 | HASH GROUP BY | | 6 | 156 | 4 (25)| 00:00:01 | | 5 | TABLE ACCESS FULL| A | 6 | 156 | 3 (0)| 00:00:01 | ----------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("T1"."C1"="T2"."C1" AND "T1"."C3"="T2"."C3MAX") Note ----- - dynamic sampling used for this statement 統計 ---------------------------------------------------------- 44 recursive calls 0 db block gets 64 consistent gets 0 physical reads 0 redo size 707 bytes sent via SQL*Net to client 420 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 4 sorts (memory) 0 sorts (disk) 3 rows processed

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

  • 回答No.2

現状のSQLでは一番単純な方法と思います WHERE句で最大値の行をなんて指定できるようになると違うのでしょうが… でも、この書き方はOracle風ですね SQL Serverなら SELCT T1.* FROM テーブルA AS T1 INNER JOIN(SELECT C1,MAX(C3) AS C3MAX FROM テーブルA GROUP BY C1) AS T2 ON T1.C1 = T2.C1 AND T1.C3 = T2.C3MAX かな? 今はOracleでもJOIN記述も出来ますが(笑)

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

質問者からのお礼

>WHERE句で最大値の行をなんて指定できるようになると違うのでしょうが… そのようなことができないかなと思い投稿した次第です。 現状できないようですね・・・。 今のSQLで構築しようと思います。ありがとうございました。

  • 回答No.1

現在のSQLで問題ないように思われます。

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

質問者からのお礼

今のSQLで問題ないようですね。 ありがとうございました。

関連するQ&A

  • SQL文作成のお願い

    前提として下記のようなテーブルがあります。 テーブル名:test フィールド: 1)id: varchar, not null 2)name: varchar 3)date: timestamp with time zone, not null このテーブルに下記のようなレコードがあります。 '00001', 'A', '2005-01-01 00:00:00' '00001', 'B', '2005-07-01 00:00:00' '00001', 'C', '2005-11-01 00:00:00' '00002', 'X', '2005-01-20 00:00:00' '00002', 'Y', '2005-07-20 00:00:00' '00002', 'Z', '2005-11-20 00:00:00' ■今やりたいこと このテーブルからidごとにdateフィールド値が最近のレコードを取得したい。 ■やってみたこと 下記SQLを発行しました。 >select id, max(date) from test group by id order by id 結果==> 00001 2005-11-01 00:00:00 00002 2005-11-20 00:00:00 実際はnameフィールドの値も取得したいのですが、group by句を使うとフィールド指定ができませんでした。 ■だめだったSQL select id, name, max(date) from test group by id order by id どのようにSQLを書けばよろしいでしょうか?

  • SQLの書き方

    SQLの書き方 SQL初心者なのですが、わからないことがあるので教えてください。 表Employees (EmployeeID,EmployeeName) 表Salary (PayDate,Amount,EmployeeID) という2つの表があるときに、次の問題があります。 問題:表Employeesから各EmployeeIDについて、SalaryのAmountの最高が300,000以上のデータを取り出し、EmployeeID,EmployeeName,Amountの最高額を表示しなさい。 答えが SELECT EmployeeID ,EmployeeName ,( SELECT MAX(Amount) FROM Salary WHERE EmployeeID=Employees.EmployeeID /*GROUP BY EmployeeID*/ ) FROM Employees WHERE EmployeeID IN ( SELECT EmployeeID FROM Salary GROUP BY EmployeeID HAVING MAX(Amount)>=300,000 ) ; となるのですが、/*と*/の間の文がいらないのはなぜですか?選択リストの中の副問い合わせで、MAX(Amount)というのがあるのでグループ化しなければならないと思うのですが、よくわかりません。

  • SQLについて

    SELECT テーブル名.A テーブル名.B FROM テーブル名 WHERE テーブル名.A = Y テーブル名.B = Z SELECT 別テーブル名.A 別テーブル名.B FROM 別テーブル という2つのSQLがあったとします。この時、別テーブルのSELECT文より取得してきた、AとBを上の式の条件(Y,Z)で両方同時に使用したい場合、どのようなSQLを書いたら良いのでしょうか? 1文にまとめて書く場合です。

  • SQL文について

    Select文についての質問です。 テーブルA,B, Cがります。  Aテーブルのカラム A1,A2, A3  Bテーブルのカラム B1, B2, B3  Cテーブルのカラム C1,C2, C3 A1=B1,A2=B2の  A3,B3 と、 A1=C1でC3がNULLでないCテーブルの件数 を一度に取得したい場合、どのようなSQL文になるでしょうか。 よろしくお願いします。

  • SQLの書き方がわかりません

    下記テーブルが access上にあります。 t1 ID 日付 01 2011/8/1 01 2011/9/1 02 2011/3/1 03 2011/5/30 t2 ID 日付 01 2011/7/1 01 2011/7/30 01 2011/8/1 01 2011/8/2 01 2011/9/2 02 2011/2/11 02 2011/3/1 02 2011/8/1 03 2011/4/30 03 2011/5/29 03 2011/6/30 このデータからt1を元に ID 日付1 日付2 01 2011/8/1 2011/8/1 01 2011/9/1 2011/8/2 02 2011/3/1 2011/3/1 03 2011/5/30 2011/5/29 というデータを取得するにはどのようなSQLを書けばよいでしょうか。 具体的にはt1とt2のIDが同じで、 t2の日付がt1の日付以下で最大のレコードと紐付けたいのです。

  • SQL GROUPで件数の一番多いレコードのみ取る

    SQL GROUPで件数の一番多いレコードのみ取る ORACLE10です。 次のようなテーブルがあります。 USER -----------テーブル名 ID,NAME,DATA----列名 1,A,any 1,A,any 1,B,any 2,C,any 3,D,any このテーブルから、IDをGROUPにして、さらに、一番使用頻度の多いNAMEを取得したいのです。 表示したいのは、IDとNAMEです。 つまり、取得結果例は次のようになります。 取得結果例 ID,NAME----列名 1,A 2,C 3,D SQL文をどのように作れば可能でしょうか? ちなみに、IDやNAMEのマスタテーブルはありません。 自分では、「(select ID, NAME, count(*) from USER group by ID, NAME) COUNT」で、COUNTを内部テーブルにして、グループ内で一番多いcount(*)をmaxで取得してみようかと思ったんですが、そこからアイデアが出ませんでした。

  • SQLについて教えてください

    お世話になっております。 以下、取得したい内容です。 この内容に対して、どのようにSQLを書けばよいか良いか教えて頂きたいです。 (1)DBの全テーブルに対して特定のカラムを取得したい。(カラム名はA,Bとする) (2)取得したカラム.Aに格納されている各値に対して、カラム.Bの各レコードの項目には何の値が格納されているか知りたい。 DBはオラクルですが、オラクルでしか使えないSQL構文はつかないようにしたいです。 自分で考えたSQLは、 SELECT A,B FROM * GROUP BY A,B ですが、そもそも全テーブルを指定する際に使用するのが、「*」では正しくないような気もします。 説明がつたなくて申し訳ございません。 宜しくお願い致します。 ・テーブルイメージ テーブル.test1 +--------+------+ | No | A | B | +--------+------+ | 01 |AA| 1 | | 02 |AA| 1 | | 03 |AB| 2 | | 04 |AB| 2 | | 05 |AC| 3 | | 06 |AC| 3 | | 07 |AC| 3 | +--------+------+ テーブル.test2 +--------+------+ | No | A | B | +--------+------+ | 01 |AA| 1 | | 02 |AA| 1 | | 03 |AB| 2 | | 04 |AB| 2 | | 05 |AC| 1 | | 06 |AC| 3 | | 07 |AC| 3 | +--------+------+ テーブル.test3 +--------+------+ | No | A | B | +--------+------+ | 01 |AA| 3 | | 02 |AA| 1 | | 03 |AC| 2 | | 04 |AC| 3 | +--------+------+

  • グループ化したSQLの書き方について

    id,stpass,tokuten,branch,dateというフィールドをもつresultというテーブルを作成しました。 最高得点(フィールド名:tokuten)は、下記SQL(クエリーで作りました)でできます。 SELECT result.id, result.stpass, Max(result.tokuten) AS tokutenの最大 FROM result GROUP BY result.id, result.stpass; ただ、最高得点(Max(result.tokuten) AS tokutenの最大)を出したと同じレコードのそれ以外のフィールド(branch,date) を表示させるSQL(クエリー)がわかりません。 何方か、ご存知の方おられましたら、ご教授ください。

  • SQL文の書き方

    お世話になっております。 現在、SQLServer2000(SP4)を使用しています。 次の結果を求めるSQL文を作りたいのですが、中々上手く行きません。 良い方法を教えて下さい。 あるテーブル(tableA)にレコードが以下のようにあるとします。 【基本コード】【大分類】【中分類】    1      1    3    1      1    4    1      2    1    2      1    99    2      18    1    3      3    2 やりたい事は、【基本コード】毎に、【大分類】【中分類】の最小値を取得したいので、下記の結果を得たいのですが、 期待する結果↓ 【基本コード】【大分類】【中分類】    1      1    3    2      1    99    3      3    2 現在考えているSQL文では、下記のようになってしまいます。 実際の結果↓ 【基本コード】【大分類】【中分類】    1     1     3    2     1     3    3     3     3 現在考えているSQL文↓ SELECT  基本コード,  MIN(大分類) AS 大分類,  (SELECT MIN(中分類) FROM tableA WHERE 大分類 = (SELECT MIN(大分類) FROM tableA) GROUP BY 大分類) AS 中分類 FROM tableA GROUP BY 基本コード 中分類を求める場合の、大分類の指定の仕方が悪いのはわかるのですが、どう直したら良いのか分からず困っています。 宜しくお願いします。

  • SQLで取得したフィールドをSQL文として利用

    お世話になっております。 MYSQLで sql_id (int PK) sql_data (text) のようなテーブル(sql_db)を持ち select sql_id from where (sql_data をsqlとして実行した結果 ) > 200 のように、フィールドから取得した値をSQLとして実行したりする方法はございますでしょうか。 ご教授よろしくお願いいたします。