質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

2回答

2893閲覧

【PostgreSQL】特定の期間・曜日・時間のデータを抽出したい

退会済みユーザー

退会済みユーザー

総合スコア0

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

0クリップ

投稿2021/04/08 08:27

##前提
PostgreSQLを使用しており、以下のようなDBがあります。

【hoge_db】

noactive_time
1202104011200
2202104011300
3202104031900
4202104051600

##やりたいこと
上記のactive_timeのデータを使って、特定の期間の、特定の曜日の、特定の時間のデータを抽出し、件数をカウントしたいです。

たとえば、直近1か月の日曜日の12時~18時のデータは何件ある、という感じです。
(2021/3/21 12-18が2件、2021/3/28 12-18が3件、というイメージ)

自分なりに調べたのですが、混乱してしまい…どうかお助けください。
active_time BETWEEN '12:00:00' AND '17:59:59'で時間帯を指定する
TO_CHAR(active_time, 'YYYY/DD/MM hh:MI:SS Dy')で曜日を表示する
COUNT~GROUP BYで集計する

SQL一文でまとめたいのですが、どのように書けばいいでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sazi

2021/04/08 08:33

active_timeの型は何ですか?
退会済みユーザー

退会済みユーザー

2021/04/08 08:49 編集

stringです。 省略して書いたのですが、実際にはactive_timeというカラムはなく、長い文字列からTO_CHAR(CAST(SUBSTR(***),as timestamp), 'YYYYMMDDhhMISS') AS active_timeで出した結果になります。 別名カラムは式に直接使えないらしいので、「active_time」と記述したところはすべて上記の式を代入する形になります。
sazi

2021/04/08 08:59 編集

元になっている項目は文字型という事でしょうか? その文字型に格納されている、文字列はどのような書式でしょうか。 混乱しているのは、active_timeへの編集も関係している感じですね。
退会済みユーザー

退会済みユーザー

2021/04/08 09:42

元の文字列は「2021040112000012345678」のような22桁の文字列です。 日付時間と細かい秒数なんだと思うのですが… 型は「character varying(22)」とありました。
sazi

2021/04/08 18:36

20桁までは、’YYYYMMDDHH24MISSUS’という書式だと推測しますが、残りの2桁が不明です。 実際の値はどのようなものですか?
guest

回答2

0

ベストアンサー

(2021/3/21 12-18が2件、2021/3/28 12-18が3件、というイメージ)

上記を出力のイメージとし、

特定の期間の、特定の曜日の、特定の時間のデータを抽出し

上記を抽出条件とした場合のSQLを考えてみます。

別名カラムは式に直接使えないらしいので

ネストさせれば使えます。
可読性の為に、先ずは目的に応じた編集を先に行い、次に条件や集計を行うようにしています。

ここでは時間帯を6時間ごとのグループにする編集を行っています。

取り敢えず条件部分はわざとコメントにしていますので、適宜利用して下さい。

SQL

1select active_date, active_day, active_timezone, count(*) as cnt 2from ( 3 select * 4 , to_date(substr(active, 1, 8), 'YYYYMMDDHH') AS active_date -- 日付 5 , to_char(to_date(substr(active, 1, 8), 'YYYYMMDDHH'), 'TMDy') AS active_day -- 曜日 6 , to_char(substr(active, 9, 6)::integer,'FM00:00:00')::time AS active_time -- 時間 7 , case substr(active, 9, 2)::integer / 6 8 when 0 then '00-06' 9 when 1 then '06-12' 10 when 2 then '12-18' 11 when 3 then '18-24' 12 end AS active_timezone -- 時間帯 13 , to_timestamp(substr(active, 1, 20), 'YYYYMMDDHH24MISSUS') AS active_timestamp -- タイムスタンプ 14 from (values 15 (1,'2021040112000000000000') 16 ,(2,'2021040113000000000000') 17 ,(3,'2021040319000000000000') 18 ,(4,'2021040516000000000000') 19 ) as hoge_db(no, active) 20) edit 21/* 22where active_date between '2021/04/01' and '2021/04/05' 23 and active_day in ('月','木','土') 24 and active_time between '12:00:00' AND '17:59:59' 25*/ 26group by active_date, active_day, active_timezone 27order by active_date, active_timezone

元の文字列は「2021040112000012345678」のような22桁の文字列です。

という事なので、桁数的に不明な部分がありますので、20桁が’YYYYMMDDHH24MISSUS’だとして、必要な桁のみをsubstrでピックアップする事にしています。

投稿2021/04/09 01:13

編集2021/04/09 05:05
sazi

総合スコア25327

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

期間や曜日や時間での絞り込みクエリーがよくある操作なのだとしたら、
いちいちvarcharとかtextとかから関数かまして加工した上での絞り込みって
レコード件数次第ではメモリに上がりきらなくなって極端に遅くなる場合も考えられそう。

式に対するインデックスを組み合わせるのはもちろんだけど、

  • 期間の絞り込み用にtimestamp型で持つ、
  • 曜日の絞り込み用に曜日カラムを持つ、
  • 時間の絞り込み用に時成分のみのintegerカラムを持つ、

って工夫をしたらいいと思った。
そういうviewを予め組んでもいいだろうし、
データ投入時点でpl/pgSQLを駆使して検索用に加工したものが
自動反映されるようにするなどの工夫もありかもしれない。

sql

1select 2 substring(t.active_time from 1 for 4) as yyyy, 3 substring(t.active_time from 5 for 2) as mm, 4 substring(t.active_time from 7 for 2) as dd, 5 substring(t.active_time from 9 for 2) as hh, 6 substring(t.active_time from 11 for 2) as nn 7from ( 8 select '202104011200' as active_time 9) as t

これで年月日時分が分離できるし、

sql

1select 2 to_timestamp(substring(t.active_time from 1 to 14), 'YYYYMMDDHH24MISS') as "タイムスタンプ", 3 extract(dow from to_timestamp(substring(t.active_time from 1 to 14), 'YYYYMMDDHH24MISS')) as "dow(0が日曜日)", 4 extract(hour from to_timestamp(substring(t.active_time from 1 to 14), 'YYYYMMDDHH24MISS')) as "hour" 5from ( 6 select '202104011200' as active_time 7) as t 8

これでtimestamp型にできるからここから加工すればいいんじゃないかと。

投稿2021/04/08 08:54

編集2021/04/09 01:24
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/04/08 11:55

回答ありがとうございます。 確かに、あらかじめカラムやviewを持つのがいいとは思うんですが…今回は突発的な調査なのと、DBは実際に会社で運用しているものなので、編集は禁止されています。(SELECTでの読み取りのみ可能)
退会済みユーザー

退会済みユーザー

2021/04/09 01:25

追記コメント内の22文字ってのに合わせてクエリーを直してみたり。 こんな感じで加工はできるので、それを踏まえて組み立てたらって話だったけど、さすがsaziさんだわ。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問