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

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

解決済

4回答

3810閲覧

SQLで、日付が1秒ずれたデータを、同一データとして扱いたい

user968

総合スコア13

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

投稿2018/09/17 02:15

編集2018/09/17 04:56

前提・実現したいこと

SQLで、以下のようなテーブルから、合格した製品の数を求めようとしています。

<列の説明>
・productは、製品のidです。
・orderは、productのうちで最初に作った製品が1、次の製品が2となります。
(productが変わった場合、orderは再度1から始まります)
・timeは、判定した時刻です
・okは、trueが合格、falseが不合格です
・machineは判定装置のidです。1と2があります。

<データの説明>
・一つの製品につき2回検査があります。
・2回とも結果がtrueなら合格です。
・「productとorderが同じでtimeも同じ」または「productとorderが同じでtimeのずれが1秒」なら同じ製品です。
・1と2の検査の順番は決まってません。

<テーブル>
product|order|time|ok|machine
|:--|:--:|--:|--:|
1|1|2018-09-10 12:00:00|true|1
1|1|2018-09-10 12:00:01|false|2
1|2|2018-09-10 12:00:09|true|2
1|2|2018-09-10 12:00:10|true|1
1|3|2018-09-10 12:00:20|false|2
1|3|2018-09-10 12:00:20|true|1
2|1|2018-09-10 12:00:35|false|1
2|1|2018-09-10 12:00:35|true|2
1|1|2018-09-11 12:00:00|false|1
1|1|2018-09-11 12:00:00|false|2

<出力したいデータ>
|合格数|
|1|

発生している問題

以下が、作成したSQLです。

SELECT count(*) FROM( SELECT order FROM table GROUP BY product,order,time HAVING SUM(CASE is_ok WHEN 'true' THEN 1 WHEN 'false' THEN 0 END) in (2))as t1 )

「GROUP BY」で製品ごとのレコードを抽出し、「HANING」で2回とも結果がtrueのレコードを抽出しています。
しかし、これでは『「orderが同じでtimeのずれが1秒程度」なら同じ製品』という条件を実現できてません。
どのようにSQLを書けばいいでしょうか。

補足情報(FW/ツールのバージョンなど)

PostgreSQL10を使ってます。

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

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

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

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

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

sazi

2018/09/17 03:15 編集

条件が不明確です。1秒程度とありますが「程度」とはどのような範囲でしょう。また、「1秒程度」の範囲にない場合は、どう扱うのですか?(共に対象にしないのか、小さい方を基準にするとか)
m.ts10806

2018/09/17 04:09

PostgreSQLをタグに追加してください
guest

回答4

0

ベストアンサー

GROUP BY order,(timeの秒が奇数なら1秒引く)
でいいのでは?
と思ったけど駄目ですね。

律儀にlagを使えば良さそうです。

sql

1with tmp as( 2SELECT ord,time, 3lag(time) over(partition by product,ord order by time,machine) as ltime 4FROM t 5where ok) 6select count(*) 7 from tmp 8 where time = ltime 9 or time = ltime + interval '1 second'

投稿2018/09/17 02:39

編集2018/09/17 08:16
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

user968

2018/09/19 08:06

ありがとうございます。lag関数は知りませんでした。とても便利ですね。 この方法でうまくいきました。
guest

0

orderは予約語なので、もし実際の項目名なら別な項目名への変更をお薦めします。

SQL

1SELECT count(*) 2FROM( 3 SELECT product, "order" 4 FROM table1 5 GROUP BY product, "order" 6 HAVING (max(time)- min(time)= interval '1 second' or max(time)= min(time)) 7 and sum(case when ok then 1 else 0 end)=2 8) tmp

投稿2018/09/18 03:53

sazi

総合スコア25173

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

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

user968

2018/09/19 07:39

ありがとうございます。実際の項目名は別なので大丈夫です。 「GROUP BY product, "order"」とすると「productとorderが同じでtimeが違っているレコード」を同じ製品に対する検査としてしまうので、結果が異なると思われます。
sazi

2018/09/19 07:48

そうなんですか。では、サンプルのorder=3は実際には無いということですか?
sazi

2018/09/19 07:55 編集

「一つの製品につき2回検査があります。」とは同一のmachineでの話ですか? それで、同一のmachineで2回OKだったら? それとも別々なmachineで都合4回行って、その内2回がOKなら合格ってことですか?
user968

2018/09/19 08:04

machine1での検査と、machine2での検査を1回ずつ行い、両方がOKなら合格です。 orderは製品を作った数(識別番号)なので、3以上もあります。
sazi

2018/09/19 08:25 編集

分かりました。では他の回答の方が適当ですね。
sazi

2018/09/19 08:28 編集

ただ、「「productとorderが同じでtimeが違っているレコード」を同じ製品に対する検査としてしまう」というのは、havingの条件で除外されていると思うんですが、結果的には正しくなかったと云うことなんですね。 ああ、別なものが含まれて正しい結果が得られないという事か
user968

2018/09/21 01:36

「同じ製品に対する検査」という集合を作る条件は、group byで指定します。 havingは集合を作った後の操作です。
guest

0

・productは、製品のidです。
・「productとorderが同じでtimeも同じ」または「productとorderが同じでtimeのずれが1秒」なら同じ製品です。

⇒パッと見、productが同じなら、同じ製品にも見えますが、
データの説明を見る限り、
productというよりproject id や cycle idみたいな捉え方になりそうですね。

なお、SQLを作る際の考え方として、
machine 1の結果テーブル
machine 2の結果テーブルが存在し、
同じ製品の結果を抽出・カウントするイメージで十分じゃないですかね。

※実際の利用状況を考えると、
machine 1 の結果のOKが2つあっても、
合格ではなさそうなので。

SQL

1SELECT COUNT( 'X' ) 2FROM table T1 3 INNER JOIN table T2 ON( 4 T2.machine = 2 5 AND T2.product = T1.product 6 AND T2.order = T1.order 7 AND T2.time <= T1.time + interval '1 second' 8 AND T2.time >= T1.time - interval '1 second' 9 ) 10WHERE T1.machine = 1 11 AND T1.ok = 'true' 12 AND T2.ok = 'true'

※見て分かると思いますが、
上記は、以下のような状況には対応していません。

productordertimeokmachineコメント
112018-09-18 12:00:00true1同一マシンの合格結果が1秒以内に複数存在
112018-09-18 12:00:01true2
112018-09-18 12:00:01true1
122018-09-18 12:00:00true1同一マシンの合格結果が2秒以内に存在し
122018-09-18 12:00:01true2間に異なるマシンの合格結果
122018-09-18 12:00:02true1
122018-09-18 12:00:03true2
132018-09-18 12:00:00true1同一マシンの合格が2つ
132018-09-18 12:00:00false2
132018-09-18 12:00:01true1

投稿2018/09/18 01:46

tomari_perform

総合スコア760

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

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

user968

2018/09/19 07:53

ありがとうございます。説明がわかりずらくて申し訳ございません。 「同じ製品」ではなく「同じ製品に対する検査結果」という意図で書きました。 machineごとの結果テーブルを抽出してカウントするのは思いつきませんでした。
guest

0

こんなかな?

SQL

1SELECT COUNT(1) 2FROM table 3WHERE ok = True 4GROUP BY order, CAST(time AS date) 5HAVING COUNT(1) >= 2 AND MAX(time) - MIN(time) <= '00:00:01'

sql_lover さんの指摘により日付もグループピング

上は題意を間違えてました。
平文(サブクエリを使わない)にこだわって書き換えました。
実行速度はおそらく遅いです。

SQL

1SELECT COUNT(1) 2FROM table AS t1 3 INNER JOIN table AS t2 4 ON t1.product = t2.product 5 AND 6 t1.order = t2.order 7WHERE t1.ok 8 AND 9 t2.ok 10 AND 11 t1.machine = 1 12 AND 13 t2.machine = 2 14 AND 15 t1.time - t2.time BETWEEN '-00:00:01' AND '00:00:01'

投稿2018/09/17 02:32

編集2018/09/17 07:32
hihijiji

総合スコア4150

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

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

退会済みユーザー

退会済みユーザー

2018/09/17 02:46 編集

下記データの場合に期待した結果を返さないのでは? order time ok machine 1 2018-09-10 12:00:00 true 1 1 2018-09-10 12:00:01 true 2 1 2018-09-11 12:00:00 true 1 1 2018-09-11 12:00:00 true 2
hihijiji

2018/09/17 03:56

日付違い 抜けてました 追記します。
退会済みユーザー

退会済みユーザー

2018/09/17 05:31

CAST(time AS date)を集約キーに追加したら 下記データの場合に期待した結果を返さないのでは? order time ok machine 1 2018-09-10 23:59:59 true 1 1 2018-09-11 00:00:00 true 2
hihijiji

2018/09/17 06:29

そもそもその場合はproductが変更になるので、同一製品とはみなされません。
hihijiji

2018/09/17 06:31

上productではなくorderでした。
hihijiji

2018/09/17 06:32

ごめんなさい何か勘違いしてました。そんなことは書いてませんね。
user968

2018/09/21 01:28

ありがとうございます。自己結合して、同じ製品への検査結果を同じレコードに入れればwhere文が使えるのですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問