• 締切済み

SQL文の作成について

下記のようなテーブルがあります. テーブル名:logdata フィールド: 1)日付: timestamp with time zone 2)発信元IPアドレス: inet 2)ポート番号: integer 具体例はつぎのようなものです. 2008/01/14 00:00:00, xxx.xxx.xxx.xxx, 445 2008/01/14 00:00:01, xxx.xxx.xxx.xxx, 135 ・ ・ ・ 2008/01/18 23:59:59, xxx.xxx.xxx.xxx, 445 今回,発信元IPアドレスは特に考慮せず, 1時間ごとの各ポートへのアクセス数を出力させたいのですが, どのようなSQLを書けばよろしいでしょうか?

みんなの回答

回答No.5

ところで最終的なレポートを、どのような方法・アプリで見るつもりでしょうか? 横に多数展開されたレポートは、非常に見づらいですよ? 縦軸はポート番号、横軸は時刻にした方が見やすいと思うし、この方法ならSQL だけでも実現可能です。というか、#2で既に回答済でしたね。

回答No.4

SQLだけで、横に展開する項目数を可変にすることは非常に困難です。 予め最大項目数を決めて固定にしておけば可能かも知れませんが、数千~数万といった単位だと、SQL文の長さの制限に掛かったり、性能が出せないSQLになります。 #1でも書きましたが、凝った表示を実現したいなら、ストアドプロシジャを使うか、アプリケーション側で編集するしかありません。

回答No.3

殆ど答えともいえるSQLは、既に提示済です。 ほんの少し変更するだけで期待した結果を得られるのですが、自分で試行錯誤する気はないのでしょうか? やる気を感じられない人に教えるのは、教える側としても教え甲斐がありません。。。 <SQL例> select to_char(日付,'YYYY-MM-DD') as YYYYMMDD, to_char(日付,'HH24') as HH, sum(case when ポートNo=123 then 1 else 0 end) as "port123", sum(case when ポートNo=333 then 1 else 0 end) as "port333", sum(case when ポートNo=555 then 1 else 0 end) as "port555" from logdata group by YYYYMMDD,HH order by YYYYMMDD,HH 存在しない日時のデータは、当然、検索結果として得られません。もし、データが存在しない日時も0件で表示したいなら、#1でも触れましたが、日付(あるいは時間も)を管理するカレンダー表を作り、LEFT JOINする必要があります。 PostgreSQLには独自機能として、集合を返すgenerate_seriesという関数があり、この関数でも日付や時刻を生成することは可能ですが、性能的にはカレンダー表を作り、適切なインデクスを定義した方がいいと思います。 =====余談===== こういったサイトで今回のような質問をする場合、表の定義(列構成とデータ型)、表のデータ、得たい結果を明記した方が、回答を得やすいです。さらには、表の定義や格納データ等をSQLで示し、回答者側がすぐにテストできるような形で掲載すれば、回答者側の負担も減り、すぐにテストできますから、多くの人から早く回答を得られる可能性があります。また、バージョンも明記しましょう。 また、「他人にSQL等を作ってもらうこと」を許している「はてな」といったサイトもあります。ポイントを購入し、回答者にポイントでお礼する仕組みですが、それだけに回答もしっかりしたものを得られます。

mochi25
質問者

補足

教えていただいた SQL はすぐに考えついたのですが, この書き方ですと sum(case when ポートNo= 以下略 を 自分で何番のポートにアクセスがあったかどうかを調べ, それらをすべて手で打たなければならないと思います. アクセスが検知されているポート(数千~数万あります)を 重複しないように横に展開する方法はありますでしょうか? 余談について: いただいたアドバイスはごもっともだと思います. 反省し,今後につなげていきたいと考えております.

回答No.2

クロス集計ですね。 SQL例を示します。 <ポート番号毎に、時間帯(2時間)別のアクセス数を得るSQL例> select ポートNo, sum(case when extract(hour from 日付) between 0 and 1 then 1 else 0 end) as "0-", sum(case when extract(hour from 日付) between 2 and 3 then 1 else 0 end) as "2-", sum(case when extract(hour from 日付) between 4 and 5 then 1 else 0 end) as "4-", sum(case when extract(hour from 日付) between 6 and 7 then 1 else 0 end) as "6-", sum(case when extract(hour from 日付) between 8 and 9 then 1 else 0 end) as "8-", sum(case when extract(hour from 日付) between 10 and 11 then 1 else 0 end) as "10-", sum(case when extract(hour from 日付) between 12 and 13 then 1 else 0 end) as "12-", sum(case when extract(hour from 日付) between 14 and 15 then 1 else 0 end) as "14-", sum(case when extract(hour from 日付) between 16 and 17 then 1 else 0 end) as "16-", sum(case when extract(hour from 日付) between 18 and 19 then 1 else 0 end) as "18-", sum(case when extract(hour from 日付) between 20 and 21 then 1 else 0 end) as "20-", sum(case when extract(hour from 日付) between 22 and 23 then 1 else 0 end) as "22-" from logdata group by ポートNo order by ポートNo <日付、ポート番号毎に、時間帯(2時間)別のアクセス数を得るSQL例> select to_char(日付,'YYYY-MM-DD') as YYYYMMDD, ポートNo, sum(case when extract(hour from 日付) between 0 and 1 then 1 else 0 end) as "0-", sum(case when extract(hour from 日付) between 2 and 3 then 1 else 0 end) as "2-", sum(case when extract(hour from 日付) between 4 and 5 then 1 else 0 end) as "4-", sum(case when extract(hour from 日付) between 6 and 7 then 1 else 0 end) as "6-", sum(case when extract(hour from 日付) between 8 and 9 then 1 else 0 end) as "8-", sum(case when extract(hour from 日付) between 10 and 11 then 1 else 0 end) as "10-", sum(case when extract(hour from 日付) between 12 and 13 then 1 else 0 end) as "12-", sum(case when extract(hour from 日付) between 14 and 15 then 1 else 0 end) as "14-", sum(case when extract(hour from 日付) between 16 and 17 then 1 else 0 end) as "16-", sum(case when extract(hour from 日付) between 18 and 19 then 1 else 0 end) as "18-", sum(case when extract(hour from 日付) between 20 and 21 then 1 else 0 end) as "20-", sum(case when extract(hour from 日付) between 22 and 23 then 1 else 0 end) as "22-" from logdata group by YYYYMMDD,ポートNo order by YYYYMMDD,ポートNo

mochi25
質問者

補足

お蔭様で SQL の知識がだいぶ深まりました.ありがとうございます. 教えていただいたコマンドに非常に満足しているのですが(特に2番目), つぎのような結果を返す SQL も教えていただければ幸いです. YYYY-MM-DD HH | port_1 | port_2 | port_3 | ... | port_k 2008-01-19 00 | 10 | 9 | 12 | .... 2008-01-19 01 | 0 | 2 | 3 | ... 2008-01-19 02 | 1 | 4 | 3 | ... ・ ・ ・

回答No.1

具体的に、何が分からないのでしょうか? ここは「仕様を提示して、SQLを作ってもらう」サイトではなく、「分からない部分を具体的に示して質問する」ことが利用規約になっています。 得たい結果が不明ですが、提示された条件だけなら、以下のようなSQLで結果を得られます。 select port_no,date_trunc('hour',acs_tmst) as tmst,count(*) as acs_cnt from logdata group by port_no,tmst order by port_no,tmst 「データが存在しない日時も、0件で表示したい」といった要件があるなら、カレンダー表を作成しておき、ジョインするといった方法になります。 また、凝った表示方法をしたいなら、SQLだけではなく、アプリケーション側やストアドプロシジャで実装した方が、処理は軽くなると思います。

mochi25
質問者

お礼

今回が初めてのデータベース経験で至らない点が多数ありましたが, また質問した際はよろしくご教授お願いいたします.

mochi25
質問者

補足

>ここは「仕様を提示して、SQLを作ってもらう」サイトではなく、「分からない部分を具体的に示して質問する」ことが利用規約になっています。 すみません. 現在,私は bash から手打ちでコマンドを打っているのですが, コマンドを改善して負担をなるべく軽くしたいと思っています. $ psql -c "select ポート番号, count (*) from ログデータ where between '日付 00:00:00' and '日付 00:59:59' group by ポート番号 order by ポート番号 上記コマンドを日付と時刻をずらしながら実行していくのは骨が折れます. 1時間当たりのポート別アクセス数を見やすい形で出力する 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のUPDATE文(WHERE)で教えて下さい

    SQLのUPDATE文(WHERE)で教えて下さい SQL初心者なのですが、どなたか教えて頂けないでしょうか・・・。 Oracle10gにSqlPlusで接続してテーブルをUPDATEしようとしています。 【テーブル1】 品番、 規格、 取引先、 日付 A1   XXX  T001   2010/01/01 A1   YYY  T002   (空白) B1   XXX  T001   (空白) C1   ZZZ  T003   (空白) 【テーブル2】 品番、 規格、 取引先、 備考 A1   XXX  T001   あああ A1   YYY  T002   いいい B1   XXX  T001   ううう テーブル1の「日付」が(空白)のレコードを対象に、 テーブル1の「品番+規格+取引先」とテーブル2の「品番+規格+取引先」が同じな場合、 テーブル1の「日付」項目に今日の日付をUPDATEしたいと考えています。 結果を以下のようにしたいです。 【テーブル1】 品番、 規格、 取引先、 日付 A1   XXX  T001   2010/01/01 A1   YYY  T002   2010/03/19 B1   XXX  T001   2010/03/19 C1   ZZZ  T003   (空白) これが実現できるSQL文を教えて下さい。 宜しくお願い致します。

  • 単純なselectが遅くなるのですが、理由がサッパリわかりません

    初めて投稿させて頂きます。 過去に、PostgreSQL 7.4.6(Linux 2.6.9-5.EL)の環境で、データ監視系のシステムを構築しました。稼働してから数年が経過しています。 このシステムのDBには数十のテーブルがあり、期待通りに動いています。 ただ、一つのテーブルのみ、時間が経過の経過と共にselectが恐ろしく遅くなる現象が発生しています。 そのテーブルのスキーマは以下です。 =# \d node_condition; Table "public.node_condition" Column | Type | Modifiers ------------------+-----------------------------+----------- node_id | integer | checktime | timestamp without time zone | ping | boolean | rtt | real | cpu | real | loadavg | real | mem | real | disk | real | snmp_w | integer | ip_w | integer | serv_w | integer | licence | integer | f_licence | integer | version | text | web_ver | text | sync | boolean | errchecktime | timestamp without time zone | ipwatchtime | timestamp without time zone | servwatchtime | timestamp without time zone | nmsdlasttime | timestamp without time zone | filemakelasttime | timestamp without time zone | 現在入力されているデータ数は51ラインです。 設計上、このテーブルは約1分間に51回updateが行われます。 主に時間系の更新です。 他のテーブルと違うところは、カラム数が少し多い、updateが頻繁に実行される、というくらいです。他のテーブルは多くても12カラムで、子のような現象は出ていません。 SQL(select)は至ってシンプルで、このテーブルしか参照しません。(select node_id,checktime ... from node_condition;) 構築時の応答速度は至って普通だったのですが、昨年の夏に異常に遅くなっていることが判明しました。 その時は、データを退避してからテーブルをDROPしてcreateし直すという荒業で解決したのですが、先日また異常に遅くなっている事に気づきました。 (この時点で原因を潰すべきだったのですが、忙しくて強引にやってしまいました。ちなみに、その時VACUUM,ANALYZEはやったのですが、効果がありませんでした。また、このシステムではVACUUM,ANALYZEが定期的に実行されています。) postgresはupdateのアルゴリズムは、他のRDBMSと違うような事が書いてありましたが、カラム数が多くなると挙動に影響が出るのでしょうか。どなたか詳しい方がいましたら、ご教授頂けると助かります。

  • SQLの書き方について教えてください。

    SQL Server2000で下記のようなSQL文を書きたいと思っています。 テーブルAとテーブルAに無関係な2個のフィールドを 持つテーブルBがあり、テーブルAのデータをテーブルBにコピー したいと考えています。その際にテーブルBの2個のフィールドに対して 決められた値を挿入したいのですがどのように記述すればよいのか わかりません。 お分かりの方お教えいただけませんでしょうか よろしくお願いいたします。 下記の記述をしています。 INSERT INTO テーブルB ( A, B, C, D ) SELECT テーブルA.A, テーブルA.A, XXX1, XXX2 FROM reserveSETdateTRN; Cに東京 Dに品川 を入れたいと思っています

  • SQLのUPDATE文に関して教えて下さい

    SQLのUPDATE文に関して教えて下さい まだまだ初心者で勉強中なのですが、ご教授をお願い致します。 2つのテーブルがあり同じ条件になったレコードのある項目を別のもう片方の項目にセットしたいのですが上手くいきません。 具体的には以下の通りです。 【テーブル1】 品番、 規格、 取引先、 日付 A1   XXX  T001   2010/01/01 A1   YYY  T002   (空白) B1   XXX  T001   (空白) C1   ZZZ  T003   (空白) 【テーブル2】 品番、 規格、 取引先、 受入日 A1   XXX  T001   2010/01/01 A1   YYY  T002   2010/03/01 B1   XXX  T001   (空白) テーブル1の「日付」が(空白)のレコードを対象に、 テーブル1の「品番+規格+取引先」とテーブル2の「品番+規格+取引先」が同じな場合、 テーブル1の「日付」項目にテーブル2の「日付」項目をUPDATEしたいと考えています。 結果を以下のようにしたいです。 【テーブル1】 品番、 規格、 取引先、 日付 A1   XXX  T001   2010/01/01 A1   YYY  T002   2010/03/01  ←ここが今回更新される B1   XXX  T001   (空白) C1   ZZZ  T003   (空白) 以前この場で教えて頂いたものを参考に以下のような感じで考えていたのですがエラーになります。 update テーブル1 set テーブル1.日付 = テーブル2.受入日 where テーブル1.日付 Is Null and (concat(concat(品番, 規格), 取引先)) in (select (concat(concat(品番, 規格), 取引先)) from テーブル2) ; ERROR at line 1: ORA-00904: "テーブル2"."受入日": invalid identifier set文のところの記述方法がわかりません。 宜しくお願い致します。

  • 2回実行のSQL文を1回にしたい

    テーブルXXXがありますその中の各フィールドは以下の通りです。 フィールド A フィールド B フィールド C まずA=0の検索をしてBの値を取り出し、新たにB=取り出した値で 検索をしたいのですがSQL文が1つにできないでしょうか? 今現在、 SELECT * FROM XXX WHERE A=0 を実行してBの値を変数Dに入れ SELECT * FROM XXX WHERE B=D と実行して全てのCの値を取り出しています よろしくお願いします。

  • SQL:TIMESTAMPの期間検索を指定するには?

    教えてください。 SQL文で日付期間の検索をしたいです。 フィールド名:tran_dataの値が、 2004/09/01 ~ 2004/09/03 のデータを検索したい。 データはTIMESTAMPで取得されています。 テーブル名:dat_history 【失敗例】 select * from web.dat_history where tran_date = '2004-08-18' 【エラーメッセージ】 日付値のストリング表記が間違っています。

  • 複数から成るテーブルを元に特定の月を集計するSQL

    MAINテーブルとITEMテーブルの2つがあります。両方のテーブルともIDが主キーです。 MAINテーブル Field #01: Alias:ID Type:INTEGER Field #02: Alias:CDATE Type:TIMESTAMP ※他にもいくつかフィールドが存在するが割愛 ITEMテーブル Field #01: Alias:ID Type:INTEGER Field #02: Alias:ITEM Type:STRING(20) Field #03: Alias:INCOME Type:NUMERIC(18,4) Field #04: Alias:OUTGO Type:NUMERIC(18,4) Field #05: Alias:REFID Type:INTEGER ここから、特定の年月を持つMAIN.CDATEのMAIN.ID(複数個存在する場合あり)とITEM.REFIDが一致するデータより、ITEM.INCOMEの総計からITEM.OUTGOの総計を差し引いた値を取得するSQL文を1回のクエリーで実装したいと考えています。 文章ではなかなか説明しづらいのですが、下記のようなSQL文をイメージしています。もちろんこれは正しい結果を返しませんので、どのようにSQL文を記述すれば正しい結果を得られるかの知恵をお貸しください。 /* 2010年1月の収支 */ select SUM(income) - SUM(outgo) from item where id = (select id from main where extract(year from cdate) = 2010 AND extract(month from cdate) = 1);

  • SQL文がDouble型として認識される

    SQL文がDouble型として認識される 質問させて頂きます。 ユーザーのポイントを引き算し、SQLにアップデートするプログラムを組んでいます。 実行すると String "UPDATE 「テーブル名」 SET 「要素名(Integer)」 " から型 'Double' への変換は無効です。 というエラーが出るのですが、SQL文の部分を何故Doubleに変換するのでしょうか? デバッグにて変数を確認し、String等をいれてみても同じエラーが出る上 SQL文は他の部分で正常に動いているものをコピーしても同じエラーが出ます。 INSERT INTO テーブル名(要素) VALUES(xxx)"であれば 「String "INSERT INTO テーブル名(要素) VALUES」 " から型 'Double' への変換は無効です。」 となります。 SQL文の記述が間違っているとは思えず、VBの記述の問題としてここで質問させて頂きました。 コードは以下の通りで、環境はVB2010 + SQL Server2008です。 回答して頂くために不足している情報がありましたらすぐに追記致します。 至らない文章ではありますが、どうかよろしくお願い致します。 Dim point As Integer point = point(Integer型) - price(Integer型) Dim strSQL As String = "UPDATE 「テーブル名」 SET 「要素(Int型)」 = '" + point + "' WHERE UserID = '" + userid(String型) + "'" cn.ConnectionString = My.Settings.ServerURL Dim cmd4 As New SqlCommand(strSQL, cn) cn.Open() cmd4.ExecuteNonQuery() cn.Close()

  • phpMyAdmin を使って以下のSQL文を記載してテープルの追加を

    phpMyAdmin を使って以下のSQL文を記載してテープルの追加をしたいのですが エラーがでます。 phpMyAdminの操作方法やSQLの知識も乏しいので EC-CUBEのテキストに従って操作しているのですが、、、、。 ------- ここから ---------- CREATE TABLE dtb_contact ( contact_id serial NOT NULL, name text, name_f text, zip01 text, zip02 text, pref integer, addr01 text, tel01 text, tel02 text, tel03 text, email text, message text, create_date timestamp without time zone, del_flg integer DEFAULT 0, customer_id integer, status integer DEFAULT 0 ); ALTER TABLE ONLY dtb_contact ADD CONSTRAINT dtb_contac_contact_id_key UNIQUE (contact_id); -----ここまで------------- 実行すると下記のようなエラーがでます ▼MySQLのメッセージ: ドキュメント #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'without time zone, del_flg integer DEFAULT 0, customer_id in MySQL の バージョンは MySQL 5.0.45なのですが 文法的にどこか間違っているのでしょうか? ご多忙のところ恐縮ですが ご教授いただければ幸いでございます。

    • ベストアンサー
    • MySQL