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

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

新規登録して質問してみよう
ただいま回答率
85.48%
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回答

1060閲覧

日時が登録されているテーブルから、開始時刻と終了時刻を出力させたい。

kabochacha

総合スコア3

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クリップ

投稿2020/11/17 10:05

編集2020/11/17 10:57

実現したいこと

DB初心者です、ご教示いただけますと幸いです。
エラー発生時刻が登録されている既存のトランザクションテーブルから、
エラー開始時刻と終了時刻を抽出するselect文を作りたいと思っています。

<使用環境>
postgreSQL12
windows10

具体的な内容としては、

SQL

1CREATE TABLE tr_machine_error ( 2 machine VARCHAR(2), 3 error_code VARCHAR(3), 4 error_date DATETIME 5);

<トランザクションテーブル>

machineerror_codeerror_date
AE012020/11/17 12:00:00
AE012020/11/17 12:10:00
AE012020/11/17 12:20:00
AE012020/11/17 12:30:00
AE022020/11/17 14:20:00
AE022020/11/17 14:30:00
AE012020/11/17 16:30:00
AE012020/11/17 16:40:00
AE012020/11/17 16:50:00
BE022020/11/17 17:00:00
BE022020/11/17 17:10:00
BE022020/11/17 17:20:00
AE032020/11/17 19:40:00
AE032020/11/17 19:50:00
AE032020/11/17 20:00:00
AE032020/11/17 20:10:00

といったテーブルが存在するとして、
出力したい結果は

machineerror_codeerror_starterror_stop
AE012020/11/17 12:00:002020/11/17 12:30:00
AE022020/11/17 14:20:002020/11/17 14:30:00
AE012020/11/17 16:30:002020/11/17 16:50:00
BE022020/11/17 17:00:002020/11/17 17:20:00
AE032020/11/17 19:40:002020/11/17 20:10:00

このように、マシンorエラーコードが切り替わったタイミングで、
開始時刻と停止時刻がわかる内容を出力させたいです。

試してみたこと

SQL

1SELECT 2 machine, 3 error_code, 4 max(error_date), 5 min(error_date) 6from 7 tr_machine_error 8group by 9 machine,error_code

maxとminで出力させようと思ったのですが、上記の表だと『マシンAとE01』が2回登場するため

machineerror_codeerror_starterror_stop
AE012020/11/17 12:00:002020/11/17 16:50:00

となってしまいます。

わかりづらく申し訳ありませんが、ご教示いただけると幸いです。
何か疑問点などあれば、ご質問いただければと思います。
よろしくお願いいたします。

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

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

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

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

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

kabochacha

2020/11/17 10:58

ご指摘ありがとうございます! 追記させていただきました、よろしくお願いいたします。
guest

回答2

0

SQLで分析関数を使って、特定の条件を満たしたレコードの前と後で別々のグループとしてグループ化する

上記の記事の応用です。
試してみたらうまく出来たので、解決済みの案件ですが
せっかくですのでコメントしました。
返信は不要です。

https://www.db-fiddle.com/f/oPHaxqhi65azrJAUzetRGT/0

SQL

1WITH SUB AS ( 2 SELECT * 3 , LAG(machine) OVER(ORDER BY error_date) AS LAG_machine 4 , LAG(error_code) OVER(ORDER BY error_date) AS LAG_error_code 5 FROM tr_machine_error 6), SUB2 AS ( 7 SELECT * 8 , CASE WHEN (machine, error_code) <> (LAG_machine, LAG_error_code) 9 THEN 1 ELSE 0 END AS FLG 10 , SUM(CASE WHEN (machine, error_code) <> (LAG_machine, LAG_error_code) 11 THEN 1 ELSE 0 END) OVER(ORDER BY error_date) AS グループ番号 12 FROM SUB 13) 14 15SELECT machine, error_code 16, MIN(error_date) AS error_start 17, MAX(error_date) AS error_stop 18FROM SUB2 19GROUP BY グループ番号, machine, error_code 20ORDER BY グループ番号

投稿2021/07/19 13:59

編集2021/07/19 14:04
takanaweb5

総合スコア358

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

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

0

ベストアンサー

error_dateは重複なく連続している前提で。

連続したerror_dateからみて、machineとerror_codeが変わるタイミングがブレークポイントです。
そのブレークポイントを個々のデータにグループの情報として割り当て、全体を集計します。
区切りの情報を生成するにはlag()やlead()のwindow関数を用います。
※文字列の結合だと組合せで同じになるかもしれないのでarray[]に変更

SQL

1with step1 as ( 2 select * 3 , lag(array[machine, error_code] ::text[], 1, array['','']) 4 over(order by error_date) lag_key 5 from tr_machine_error 6), step2 as ( 7 select case when array[machine, error_code] ::text[] != lag_key then error_date end error_start 8 from step1 9) , step3 as ( 10 select error_start 11 from step2 12 where error_start is not null 13) , step4 as ( 14 select error_start, lead(error_start) over(order by error_start) lead_error_start 15 from step3 16) 17select machine, error_code, error_start, max(error_date) as error_end 18from tr_machine_error left join step4 19 on tr_machine_error.error_date >= step4.error_start 20 and (tr_machine_error.error_date < lead_error_start or lead_error_start is null) 21group by machine, error_code, error_start 22order by error_start

・解説
**step1:**lag()を用い直前のmachine, error_codeを取得します。
**step2:**step1の情報を元にブレークしている場所のみerror_startを設定します。
**step3:**step4で使用するlead()用にerror_startが設定されている情報のみにします。
**step4:**lead()を用いて、error_startでグルーピングする範囲を作成します。
**最終:**step4の情報と結合し、集計によってerror_endを求めます。

ぱっと思いついて組み立てただけなので、観点を変えると簡潔な記述があるかもしれません。

DB初心者です

初心者レベルならSQLのみでは解決できません。
テーブルを日時順に読み込んで、start、endを作成するような処理になるはずです。
指針もなくこれを丸投げするプロジェクトだったりすると、前途多難ですね。

投稿2020/11/17 11:17

編集2020/11/17 14:52
sazi

総合スコア25195

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

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

kabochacha

2020/11/19 01:12

ありがとうございます。試してみたところ、無事できました! ですが、確かにDB初心者がSQLのみで解決するような内容ではないと思いました。 最初から開始時刻と終了時刻がわかるようなデータのとり方が一番いいのですが、 テーブル構造など一旦見直しつつ、考えてみます。 ありがとうございました。
sazi

2020/11/19 01:26 編集

集計で括る為の情報が不足しているので、tr_machine_error に追加する際にそういった情報(例えばエラーID)を設定するだけで、複雑な集計ではなくなります。
kabochacha

2020/11/24 07:32

ご無沙汰しております。 まだ、ご回答いただけそうであればご質問させていただきたいです! やはり、errorの開始時間と、終了時間がわかるようなプログラムがないようで 既存のtr_machine_errorテーブルの構造を見直すという方向になり、カラムを追加しようと 思っています。アドバイスいただきました、 >集計で括る為の情報が不足しているので、tr_machine_error に追加する際にそういった情報(例えば?>エラーID)を設定するだけで、複雑な集計ではなくなります。 エラーIDとは、シーケンスのようなものでしょうか? また、上記の質問とは別に、tr_machine_errorは必ず10分ごとにレコードが吐かれるようで、 その仕組みを使って、『直前のレコードと比較して、差が10分ではない場合、そのレコードを終了日時とする』みたいな条件を考えているのですが、こちらもSQLで可能なのでしょうか。
sazi

2020/11/24 10:03

> エラーIDとは、シーケンスのようなものでしょうか? シーケンスではありません。 グループ毎に一意となるものをルールに基づき自前で発番するものを想定しています。 >tr_machine_errorは必ず10分ごとにレコードが吐かれるようで、その仕組みを使って、『直前のレコードと比較して、差が10分ではない場合、そのレコードを終了日時とする』みたいな条件を考えているのですが、こちらもSQLで可能なのでしょうか。 10分間隔で行われる処理とは別な処理で行うという事でしょうか? いまいち仕様が把握できませんが、SQLでは無理と言うほどでは無いと思います。 だけど、出来ない事は出来ないと言う勇気も必要ですよ。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問