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

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回答

7874閲覧

postgresで歯抜けとなっている状態のデータを補完しつつ取得したい

jee

総合スコア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/10 00:45

編集2018/09/10 00:53

閲覧いただきありがとうございます。

現在、テーブル上に存在する日付ごとの入力データを月別集計データにして抽出して出力しようとしているのですが、データのある箇所のみの抽出しかできておらず困っています。
値が存在しない歯抜けの部分に0と挿入したいのですがよい方法はありますでしょうか。
列はそれぞれdate型、bigint型となっています。

テーブルの状態

iddateinsert_count
12018-01-0230
22018-01-0770
32018-02-0130
42018-02-04100
52018-02-1160
62018-02-20110
72018-04-0230
82018-04-1370
92018-07-05150
102018-07-1270
112018-07-20110
112018-07-2770

現在取得できている状態

ymcount
201801100
201802300
201804100
201807400

理想

ymcount
201801100
201802300
2018030
201804100
2018050
2018060
201807400

上記のデータを取得しているSQL文

実行SQL

sql

1SELECT to_char(date, 'YYYYmm') as ym, SUM(insert_count) as count  2FROM orders WHERE to_char(date, '%y') = to_char(DATE '2018-01-01', '%y') GROUP BY to_char(date, 'YYYYmm')

試したこと

sql

1--対象となる年の月毎データを生成してLEFT JOINしてみる -- 2SELECT '201801' + s.i as months , result.count FROM generate_series(0,11) AS s(i) 3LEFT JOIN ( 4SELECT to_char(date, 'YYYYmm') as ym, SUM(insert_count) as count  5FROM orders WHERE to_char(date, '%y') = to_char(DATE '2018-01-01', '%y') GROUP BY to_char(date, 'YYYYmm') 6) AS result ON s.i::text = result.ym 7 8-- 生成したマスタデータはInteger型で素の状態だと結合できないため明示的にtext型にしています --

ですので上記のようにマスタデータを生成して実行しようとすると初めのSELECT内でのs.iが使えず(GROUP BYしろというエラー)、どうすればいいのでしょうというのが現状です。

補足情報

ではs.iを除いてデータだけでも確認してみようと思いSELECTでデータのある月を確認してみるとなぜかデータが取得できておらずそもそもがダメそうな感じもしています

実行SQL

sql

1SELECT '201801' as months , result.count FROM generate_series(0,11) AS s(i) 2LEFT JOIN ( 3SELECT to_char(date, 'YYYYmm') as ym, SUM(insert_count) as count  4FROM orders WHERE to_char(date, '%y') = to_char(DATE '2018-01-01', '%y') GROUP BY to_char(date, 'YYYYmm') 5) AS result ON s.i::text = result.ym
結果
monthscount
2018010

monthsの部分がunknown型、countの部分がbigint型となっています。


postgresを始めたてでわかりにくい部分もあるかもしれませんがご教授いただけますとうれしいです。よろしくお願いします。

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

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

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

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

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

guest

回答2

0

generate_series()を使用するのは、m6uさんと同じなのですけど、質問にあるSQLは文法エラーだったり、書式(%yとか)がMySQLのものだったりしています。(dateは予約語なので項目名としては相応しくありませんよ)

以下は、開始の日付と取得する年数をパラメータとして、取得するサンプルです。

SQL

1with para as( 2 select '2018-01-01'::date as start_date, '1'::text as range 3) 4, ymd as ( 5 select generate_series(start_date, start_date + (range || ' year')::interval, '+1 month')::date as ymd from para 6) 7SELECT to_char(ymd, 'YYYYmm') as ym, SUM(coalesce(insert_count,0)) as count  8FROM ymd left join orders on ymd.ymd=orders.date 9GROUP BY to_char(ymd, 'YYYYmm')

投稿2018/09/10 01:40

編集2018/09/10 01:54
sazi

総合スコア25195

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

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

退会済みユーザー

退会済みユーザー

2018/09/10 01:41

あぁ、%Yってそういうことかぁ
jee

2018/09/10 02:20

%yはMySQLの記述法なんですね。お恥ずかしい… いろいろなRDBMSのサイトを参考にしながら作成していたので気づきませんでした。ありがとうございます!
sazi

2018/09/10 02:25

%yの指定だと意図する結果にはなりません。 テストするサンプルが少なすぎるから検知できていないのです。
sazi

2018/09/10 02:26

to_char(DATE '2018-01-01', '%y') 上記部分は文法エラーですけど、エラーにはなりませんか?
sazi

2018/09/10 02:30

テストデータを増やさないなら、せめて条件部分の記述をselectして意図通りかを確認したほうが良いですね。
jee

2018/09/10 02:51

返信ありがとうございます。 pgAdmin IIIにて実行しているのですが、初めに月別データを取得するSQLとして掲載した文はエラーを吐かずに通って結果が取得できていたので間違いであることに気づきませんでした。
退会済みユーザー

退会済みユーザー

2018/09/16 06:41

select句での集合関数の使用は、非推奨機能で削除予定ですので、マイナス投票します。 https://www.postgresql.jp/document/9.6/html/xfunc-sql.html >現在、集合を返す関数は問い合わせの選択リスト内でも呼び出すことができます。 >問い合わせ自身によって生成する各行に対し、集合を返す関数が呼び出され、 >関数の結果集合の各要素に対して出力行が生成されます。 >ただし、この機能は現在では推奨されておらず、今後のリリースでは削除される可能性があります
sazi

2018/09/16 13:34 編集

>sql_loverさん 削除される可能性があるから非推奨ということで、削除予定ではありません。 同じ集合関数であるgenerate_subscripts()などは基本的な例ではselect で紹介されています。 集合関数と似た動きのunnest()などは複数項目がある場合には、selectで使用したりしますので、 動作に問題があるという訳ではなく、バージョンアップした場合の移植に手間が発生するという事ですし、可読性を優先させるような場合には、あまり気にする必要は無いかと思いますけどね。
guest

0

ベストアンサー

9.24. 集合を返す関数
にある、generate_series()を駆使すれば、連番で値の集合を作れます。

sql

1select to_char(s.a, 'YYYYMM') as ym 2from ( 3 select * from generate_series('2018-01-01'::timestamp, '2018-12-01'::timestamp, '+1 month'::interval) 4) as s(a)

このテーブルに対してleft joinすればよいです。
値なないことを想定してcoalesce(result.count, 0)などとします。

sql

1select d.ym, coalesce(r.count, 0) as count 2from ( 3 select to_char(s.a, 'YYYYMM') as ym 4 from ( 5 select * from generate_series('2018-01-01'::timestamp, '2018-12-01'::timestamp, '+1 month'::interval) 6 ) as s(a) 7) as d 8left join ( 9 SELECT to_char(orders.date, 'YYYYMM') as ym, SUM(orders.insert_count) as count 10 FROM orders 11 WHERE date_part('year', orders.date) = 2018 12 GROUP BY to_char(orders.date, 'YYYYMM') 13) as r on d.ym = r.ym

で動きますでしょうか。(動作テストできてませんけど。)
2018年のデータだけ集計したいように見えたので、
date_part(text, timestamp)()を使えば良さそうかなと。

投稿2018/09/10 01:08

編集2018/09/10 02:06
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

jee

2018/09/10 02:15

回答ありがとうございます。 提示してくださったSQLで実行でき、動作も確認できました!ありがとうございます。 値のない部分には0を追加していくという処理にすればいいんですね
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問