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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

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

5874閲覧

指定した日付のn年分、nか月ぶんのデータを取得したい

pro-poke5

総合スコア46

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

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

投稿2017/04/26 07:35

こんにちわ
sql初心者です
DBはpostgres
VS2010でかいてます

指定した日付から1年後、2年後
または2か月後や5か月後、3日分や10日分のテーブルを取得したいです

テーブルの中身はこんなかんじです
イメージ説明

たとえば

sql

1 2 SELECT '2014' as TRANSITION_YEAR, sum_date as TRANSITION_COUNT ,user_cnt as MEMBER_NO 3 FROM tt_s_umlist 4 WHERE sum_date = '2014-12-31'; 5

これだと本当に2014-12-31のuser_cntのデータ1行のみ取得できます
イメージ説明

これを2年間、5年間など指定した年数の同じ日付のuser_cntを取得して表示させたいです
変数xに「2」年間、「5」年間といった風に何年分取得したいのかの、数字のみの変数はあります

ちなみに今は具体的な数字を入れてますが'2014'と'2014-12-31'は変数になります

イメージとしては2014(変数)年(2014-12-31)から3(変数)年間取得したいってしたら
2014 2014-12-31 1050
2015 2015-12-31 2010(適当な数字です)
2016 2016-12-31 3020(適当な数字です)
と3行表示できればいいです

説明下手ですみません
できたら同じ要領で
2014-04-01から3か月取得したいとしたら
2014-04-01のuser_cnt
2014-05-01のuser_cnt
2014-06-01のuser_cnt
と3行取得したいです

アドバイスおねがいいたします

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

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

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

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

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

guest

回答4

0

うん…年月日分かれてるし…解決したい課題がよくわからないのですが。


年単位の絞り込み

SQL

1SELECT * 2FROM tt_s_umlist 3WHERE 4sum_year BETWEEN @TargetYear - @Offset AND @TargetYear 5AND sum_month = @TargetMonth 6AND sum_day = @TargetDay

もしも受け取ってくる変数の日付2014-12-31が変更できないなら
日付型から年月日を算出しましょう。

SQL

1SELECT * 2FROM tt_s_umlist 3WHERE 4sum_year BETWEEN EXTRACT(year FROM @TargetDate) - @Offset AND EXTRACT(year FROM @TargetDate) 5AND sum_month = EXTRACT(month FROM @TargetDate) 6AND sum_day = EXTRACT(day FROM @TargetDate)

月単位の絞り込み

少し年またぎとかが面倒になりますね。
sum_dateのインターバルを定義して期間を作り絞り込み、日付だけ指定すればいいでしょう。

SQL

1SELECT * 2FROM tt_s_umlist 3WHERE 4sum_date BETWEEN @TargetDate - interval '2 months' AND @TargetDate 5AND sum_day = @Day

又は

SQL

1SELECT * 2FROM tt_s_umlist 3WHERE 4sum_date BETWEEN @TargetDate - interval '2 months' AND @TargetDate 5AND sum_day = EXTRACT(day FROM @TargetDate)

ただ、パラメータとしてのintervalの渡し方はちょっとわからないですね…うーん…文字列にすればいいのかな…
ちょっとクエリの実行条件がわからないので、それより先を考えても仕方がないのでいったんここまで。


蛇足ですが、SQL文上で日付を直書きしたい場合は以下で大丈夫です。

SQL

1SELECT * FROM tt_s_umlist WHERE 2sum_date BETWEEN date '2014/12/01' AND date '2017/12/01' 3AND sum_month = 12 4AND sum_day = 1;

投稿2017/04/27 04:38

haru666

総合スコア1591

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

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

Zuishin

2017/04/27 04:42

between は使ってはいけないそうです。なぜなら、2017/12/01 0:00:00 は含まれるけれど 0:00:01 は含まれないために見つけにくいバグの原因になることがあるそうです。
haru666

2017/04/27 04:47 編集

postgresql で date は時間数の精度が含まれていないので問題ないはずです。 ので、便利に書いていいのではないかと。 サーバー依存なコードを書くなというなら、確かにそうですが… 以下間違えてました。忘れてください。タイムスタンプ型だと、00:00:01は切り上げられますね。。。 date型なら安全ですが。 --- 仮に2017/12/01をタイムスタンプで評価する場合も2017/12/01 00:00:00 ~ 23:59:59 の範囲内なら2017/12/01に丸められます。
haru666

2017/04/27 04:51

timestampからdateへの型変換 ⇒ 時分数は切り捨てられる timestamp型でdateを評価 ⇒ 00:00:01以降は当日が含まれない 動作別のようです。 型の混同が起きるようなコードはダメそうですね…
haru666

2017/04/27 04:57

ん…? 考えてみたらBETWEEN使わなくても timestampで比較したらダメですよね…? すみません、BP教えてもらってもいいでしょうか。
Zuishin

2017/04/27 08:27

私の回答も <= が使われていますね。< と書いたつもりで間違えていました。 時間の精度が含まれていないのでおっしゃる通り問題ありません。 問題ありませんが……心がけるよう言われたことです。
haru666

2017/04/28 01:22

なるほど。 確かにタイムスタンプのデータとDate型で扱いが異なるため、それは重要なことかもしれませんね。 タイムスタンプ型の場合日付的には範囲が必要で、BETWEENで「開始日~終了日+1日」とした場合、00:00:00時のみ翌日が含まれてしまうため、以上~未満で比較しなければなりません。 そういう意味では確かに常日頃のミスを避けるためにはBETWEENを使うべきではないですね。 私のチームは冗長ですが、日付とタイムスタンプ両方登録しています。 ほぼ全てのテーブル(サイズにピーキーでないもの)以外はルールとしてタイムスタンプを持っているので、日付や時間を目的とするテーブルには冗長ですが別の列を付加して、そちらにインデックスを張っています。 正しいかどうかはわかりませんが…。それによってタイムスタンプの比較文を無くしています。
guest

0

sum_yearとsum_monthlyとsum_dayを使いました。

create temp table t_hoge (sum_year int2, sum_monthly int2, sum_day int2, sum_date date, user_cnt int);

sql

1-- 2年間、5年間など指定した年数の同じ日付のuser_cntを取得 2-- 2014-12-31から3年間 3 4select sum_year, sum_date, user_cnt from t_hoge 5where sum_year >= substr('2014-12-31',1,4)::numeric and sum_year < substr('2014-12-31',1,4)::numeric + 3 6and sum_day = substr('2014-12-31',9,2)::numeric; 7 8-- 2014-04-01から3か月取得 9 10select sum_year, sum_date, user_cnt from t_hoge 11where sum_year between to_char('2014-04-01'::date,'YYYY')::numeric and to_char((date '2014-04-01' +interval '3 month'),'YYYY')::numeric 12and not (sum_year = to_char('2014-04-01'::date,'YYYY')::numeric and sum_monthly < substr('2014-04-01',6,2)::numeric) 13and not (sum_year = to_char((date '2014-04-01' +interval '3 month'),'YYYY')::numeric and sum_monthly >= to_char((date '2014-04-01' +interval '3 month'),'mm')::numeric) 14and sum_day = substr('2014-04-01',9,2)::numeric;

投稿2017/04/27 00:35

編集2017/04/27 00:59
A.Ichi

総合スコア4070

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

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

0

ベストアンサー

PostgreSQL による日付・時刻・時間の計算・演算のまとめ がわかりやすいと思います。

SELECT '2014' as TRANSITION_YEAR, sum_date as TRANSITION_COUNT ,user_cnt as MEMBER_NO FROM tt_s_umlist WHERE sum_date >= CAST('2014-12-31' AS DATE) AND sum_date <= CAST('2014-12-31' AS DATE) + CAST('2 months' AS INTERVAL);

追記

AND sum_date < CAST('2014-12-31' AS DATE) + CAST('2 months' AS INTERVAL);

< と間違えて <= と書いていました。

投稿2017/04/26 22:58

編集2017/04/27 08:25
Zuishin

総合スコア28660

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

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

0

C#を利用してよいのであれば、
例えば
2014(変数)年(2014-12-31)から3(変数)年間取得したい場合

SQL

1SELECT '2014' as TRANSITION_YEAR, sum_date as TRANSITION_COUNT ,user_cnt as MEMBER_NO 2 FROM tt_s_umlist 3 WHERE sum_date = '2014-12-31' 4 OR sum_date = '2015-12-31'; 5 OR sum_date = '2016-12-31';

というSQLとなるので、
このSQL文を作るC#の箇所をいじってやればよいと思われます。
基本的なSQLの部分

SQL

1SELECT '2014' as TRANSITION_YEAR, sum_date as TRANSITION_COUNT ,user_cnt as MEMBER_NO 2 FROM tt_s_umlist

はそのまま保持しておいて、
WHERE句を作る関数なんかを準備してやればよいと思います。

C#

1 2// ○年間を指定した場合 3public string makeWhere(string from, string term){ 4 var where = ""; 5 var year = from.substring(0,4); 6 var flg = true; 7 for(int i=1; i<=int.Parse(term); i++){ 8 var yearInt = int.Parse(year) + i 9 if(flg){ 10 // 初回の頭はWHERE 11 where += " WHERE sum_date=" + yearInt.toString(); 12 }else{ 13 // 2回目からはOR 14 where += " OR "; 15 } 16 flg = false; 17 } 18} 19

みたいな感じでしょうか・・・
検証してないので動かないと思いますが、
泥臭い書き方だと考え方はそんな感じです。

sum_dateの型がstringじゃなければもっとよい方法が・・・

投稿2017/04/26 08:44

s.t.

総合スコア2021

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

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

Zuishin

2017/04/27 00:38

sum_date のカラム名の下に date と書いてあるので日付型だと思いますよ。
s.t.

2017/04/27 07:25

うおおお、ほんとうだ、超はずかしい・・・
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問