🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
PostgreSQL

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

Amazon Redshift

Amazon Redshiftは、Amazon社が提供する 高速かつ完全マネージド型でペタバイト規模の クラウドデータウェアハウスサービスです。

Q&A

解決済

3回答

8581閲覧

SQLにて指定日付以前、かつ最新のデータを1件取得したいです。

yowayowanitohei

総合スコア31

PostgreSQL

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

Amazon Redshift

Amazon Redshiftは、Amazon社が提供する 高速かつ完全マネージド型でペタバイト規模の クラウドデータウェアハウスサービスです。

0グッド

0クリップ

投稿2021/03/22 04:33

編集2021/03/22 04:59

前提・実現したいこと

現在下記のようなテーブルが存在しております。

テーブル・・・
ID |名前|日付
01|田中|3/16
02|田中|3/15
03|田中|3/14
04|山田|3/17
05|山田|3/16
06|鈴木|3/15
07|鈴木|3/14
・・・

名前が田中かつ日付が3/15日以前で最新を1件
名前が鈴木かつ日付が3/14日以前で最新を1件

上記のような検索を実行し、下記の結果を得たいと考えております。

ID |名前|日付
02|田中|3/15
07|鈴木|3/14

試したこと

SELECT *
FROM テーブル AS テーブルA
INNER JOIN (SELECT 名前,MAX(日付)AS 最新日付 FROM テーブル
WHERE (日付 <= ‘2021-03-15 00:00:00’ AND 名前 = ‘田中’)
GROUP BY 名前 AS テーブルB
ON テーブルA.名前 = テーブルB.名前
AND テーブルA.日付 = テーブルB.最新日付

ーーー
上記のような形で一応取ってくることはできましたが、
かなりスピードが遅く困っております・・・
SQLに関する理解不足で読みにくいSQLになってしまい大変失礼ですが、
この場合の正しいSQLの書き方についてご回答をお願いしてもよろしいでしょうか。

また、もし可能であれば1回のSQLで
名前が田中かつ日付が3/15日以前で最新を1件」「名前が鈴木かつ日付が3/14日以前で最新を1件」
を同時に抽出する方法などありますでしょうか。

すみませんがどうぞよろしくお願いします。

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

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

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

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

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

sazi

2021/03/22 04:53 編集

DBはMySQL、Postgresの何れですか? それから、インデックスと実行計画の結果も質問に追記して下さい
yowayowanitohei

2021/03/22 04:55

タグ付けややこしくてすみません。。。 Postgresになります。
yambejp

2021/03/22 04:58 編集

「より前(指定日を含まない)」なのですか 「以前(指定日を含む)」なのでしょうか? 想定見る限り後者のようですが、表題がより前となっているので・・・ それと同じ名前で同じ日付のデータは存在しないことは保証されていますか?
yowayowanitohei

2021/03/22 04:58

「以前(指定日を含む)」になります。 すみませんが、どうぞよろしくお願いいたします。
guest

回答3

0

ベストアンサー

SQL

1SELECT * 2FROM テーブル 3where (名前, 日付) in ( 4 select 名前, MAX(日付) 5 FROM テーブル t inner join ( 6 select * from (values 7 ('田中', '2021-03-15' ::date) 8 ,('鈴木', '2021-03-14' ::date) 9 ) as w(指定名前,指定日付) 10 ) p 11 on t.名前=p.指定名前 and t.日付<=p.指定日付 12 group by 名前 13 )

※性能を求めるなら(名前,日付)のインデックスが必要です。
追記

Postgresのバージョンが8.0との事なので、パラメータの指定が分かりにくくなりますが、unnest()を使用した例です。

SQL

1SELECT * 2FROM テーブル 3where (名前, 日付) in ( 4 select 名前, MAX(日付) 5 FROM テーブル t inner join ( 6 select 7 unnest(array['田中','鈴木']::text[]) as 指定名前 8 , unnest(array['2021-03-15', '2021-03-14']::date[]) as 指定日付 9 ) p 10 on t.名前=p.指定名前 and t.日付<=p.指定日付 11 group by 名前 12 )

※手元には8.0の環境はありませんので、確認は出来ておらず、エラーになるかもしれません。

他のセッションの影響を受けないように一時テーブルをパラメータに利用するようにすると、SQLを動的に変更する必要は無くなります。

SQL

1CREATE TEMPORARY TABLE para ( 2 指定名前 text 3, 指定日付 date 4) ON COMMIT DELETE ROWS 5;

SQL

1insert into para values 2 ('田中', '2021-03-15') 3,('鈴木', '2021-03-14') 4; 5SELECT * 6FROM テーブル 7where (名前, 日付) in ( 8 select 名前, MAX(日付) 9 FROM テーブル t inner join para p 10 on t.名前=p.指定名前 and t.日付<=p.指定日付 11 group by 名前 12 ) 13;

投稿2021/03/22 05:16

編集2021/03/22 08:25
sazi

総合スコア25327

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

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

yowayowanitohei

2021/03/22 07:10

丁寧なご回答ありがとうございます。 一点だけ追加でご質問させていただきたいのですが、 values ('田中', '2021-03-15' ::date) ,('鈴木', '2021-03-14' ::date) 上記箇所にてsyntaxerrorが発生してしまいます。 ERROR: syntax error at or near "," 行 8: ,('鈴木', '2021-03-14' ::date) https://www.postgresql.jp/document/9.4/html/queries-values.html ドキュメントでValuesリストの例代を試しに実行してみたのですが、 同じ箇所でエラーが発生してしまいます。。 VALUES (1, 'one'), (2, 'two'), (3, 'three'); 行 1: SELECT * FROM (VALUES (1, 'one'), (2, 'two'), (3, 'three')) ... この場合の対処法などご存知でしたら大変お手数をおかけしますが お伺いしてもよろしいでしょうか。 どうぞよろしくお願いします。
sazi

2021/03/22 08:33

追記しました
guest

0

たとえばウィンドウ関数を利用するのはどうでしょうか?

SQL

1SELECT 2 ID, 3 名前, 4 日付 5FROM ( 6 SELECT 7 ID, 8 名前, 9 日付, 10 RANK() OVER (PARTITION BY 名前 ORDER BY 日付 DESC) AS rnk 11 FROM テーブル 12 WHERE (名前 = '田中' AND 日付 <= '2021-03-15') 13 OR (名前 = '鈴木' AND 日付 <= '2021-03-14') 14) AS t 15WHERE rnk = 1

投稿2021/03/22 08:43

neko_the_shadow

総合スコア2349

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

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

0

sql

1select * from tbl 2where (name,d) in ( 3select name,max(case when d>'2021-03-15' then 0 else d end) as d from tbl 4group by name 5having name='田中' 6union all 7select name,max(case when d>'2021-03-14' then 0 else d end) as d from tbl 8group by name 9having name='鈴木' 10)

投稿2021/03/22 05:09

yambejp

総合スコア116694

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問