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

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

新規登録して質問してみよう
ただいま回答率
85.35%
SQL Server

SQL Serverはマイクロソフトのリレーショナルデータベース管理システムです。データマイニングや多次元解析など、ビジネスインテリジェンスのための機能が備わっています。

Q&A

解決済

4回答

2217閲覧

自己結合時の結合条件について

ttt_xxx

総合スコア1

SQL Server

SQL Serverはマイクロソフトのリレーショナルデータベース管理システムです。データマイニングや多次元解析など、ビジネスインテリジェンスのための機能が備わっています。

0グッド

0クリップ

投稿2020/06/08 03:17

編集2020/06/08 04:43

前提・実現したいこと

1つのテーブルにあるカラムの最大値を取得したいです。
最大値(最新日)を取得したいカラムは日付_1、日付_2で、その両方の値を取得したいのですが、結合条件を以下とした場合の書き方がいまいち分からず困っております。

取得したいテーブルはこちらです。
テーブル名:table_a

実施したいこと
①nameとA_numberに該当するそれぞれの日付_1と日付_2の最新日を取得したい。
②サブクエリにて結果を取得した後、他のカラム(id)が取得できていないためidも最終的に取得したいです。

----------------------------
| id | name | A_number | 日付_1 | 日付_2 |
----------------------------
| 1 | カラム_1 | A1 | 2020-01-01 | 2020-01-05 |
----------------------------
| 2 | カラム_1 | A1 | 2020-01-02 | 2020-01-01 |
----------------------------
| 3 | カラム_1 | A1 | 2020-01-03 | 2020-01-01 |
----------------------------
| 4 | カラム_1 | A1 | 2020-01-04 | 2020-01-01 |
----------------------------

想定の結果(最終的に取得したい結果)
----------------------------
| id | name | A_number | 日付_1 | 日付_2 |
----------------------------
| 1 | カラム_1 | A1 | 2020-01-01 | 2020-01-05 |
----------------------------
| 4 | カラム_1 | A1 | 2020-01-04 | 2020-01-01 |
----------------------------

発生している問題

なにも取得できない

実施したSQL

SELECT id, name, A_number, 日付_1, 日付_2 FROM table_a AS table_1 INNER JOIN (SELECT name AS NAME, A_number AS B_number, MAX(日付_1) AS Date1_B, MAX(日付_2) AS Date2_B FROM table_a GROUP BY name,A_number) AS table_2 ON table_1.name = table_2.name AND table_1.A_number = table_2.B_number AND table_1.日付_1 = table_2.Date1_B AND table_1.日付_2 = table_2.Date2_B

試したこと

結合条件を
table_1.name = table_2.name
AND table_1.A_number = table_2.B_number
AND table_1.日付_1 = table_2.Date1_B
または
table_1.name = table_2.name
AND table_1.A_number = table_2.B_number
AND table_1.日付_2 = table_2.Date2_B
した場合は、nameとA_numberに該当する日付_1または日付_2の最新日が取得できます。

また、サブクエリで結果を取得する際は日付_1、日付_2両方とも最新の日付を取得することができました。

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

SQLServerを使用しております。
SQLServer2017、SQL Server Developer
操作はWINDOWS10
SQLのバージョンは14.0.2027.2を使用しております。

初歩的な質問で申し訳ございません。
分かる方おりましたらご教示のほどよろしくお願いいたします。

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

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

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

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

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

sazi

2020/06/08 04:01

ID取得するとして、日付_1と日付_2の最大のIDが違っている場合はどうするのですか?
ttt_xxx

2020/06/08 04:16

Orlofsky様 申し訳ございませんでした。 SELECT結果(想定の結果(最終的に取得したい結果))を記載いたしました。 アドバイスありがとうございます。
ttt_xxx

2020/06/08 04:18

sazi様 最大IDは取得する予定ではなく、最大値が欲しいのは日付_1と日付_2なのです……。 ご質問の意図が誤っていたら申し訳ございません。
Orlofsky

2020/06/08 04:28

CREATE TABLE文とINSERT文に修正してください、って書いたのを理解できませんか?
sazi

2020/06/08 04:31

> idも最終的に取得したいです。 と質問にはありますが? サブクエリーで出来ているのに、結合で行いたい理由は何ですか?
sazi

2020/06/08 04:34

ひょっとして、日付1または日付2のうち大きい方での最大値って事ですか?
ttt_xxx

2020/06/08 04:55

Orlofsky様 すみません、文にということはtableとして書くのではなくSQLを書いたほうがよいということでしょうか? 気が急いてしまい、結果のみ追記してしまいました。 申し訳ございません。 少々お待ちください。
ttt_xxx

2020/06/08 04:58

sazi様 >>サブクエリーで出来ているのに、結合で行いたい理由は何ですか? サブクエリで取得した結果とこのテーブルに含まれているほかのカラムを表示したかったため、結合にしておりました。 >>日付1または日付2のうち大きい方での最大値 いえ、日付1と日付2両方の最大値を取得したいのです……。
Orlofsky

2020/06/08 05:11

SQLでSELECTを実行する為にはCREATE TABLEが実行されてテーブルが存在していなければなりません。SELECTを実行した時にテーブル内に存在するデータを取得される為には、既にデータがINSERTされていなければなりません。
ttt_xxx

2020/06/08 18:41

Orlofsky様 申し訳ございません。 次また質問があったときは記載いただいたように詳しく記載しようかと思います。 ご教示いただきありがとうございました。
ttt_xxx

2020/06/08 18:43

ベストアンサーは一番最初に詳しくご教示いただいた方にさせていただきました。 申し訳ございません。 言葉少なく、説明不足の中ご回答いただきました皆様ありがとうございました。
guest

回答4

0

遅ればせながら参戦
そもそも論として
・「日付2で最大をとったときの日付1」
・「日付1で最大をとったときの日付2」
は完全にゴミデータだと思うんですが

nameA_number日付_1id_1日付_2id_2
カラム_1A12020-01-0442020-01-051

↑理想の出力はこれではだめなんですか?
最大値が1行に完結している場合は1行になったりするので上の理想は微妙な気がするんですが。

sql

1CREATE TABLE #table_a 2 ( 3 TableID int NULL, 4 xName nvarchar(50) NULL, 5 A_Number nvarchar(50) NULL, 6 日付_1 datetime NULL, 7 日付_2 datetime NULL 8 ) ON [PRIMARY] 9 10insert into #table_a(TableID,xName,A_Number,日付_1,日付_2) 11 select 1 , 'カラム_1', 'A1' , '2020-01-01', '2020-01-05' 12insert into #table_a(TableID,xName,A_Number,日付_1,日付_2) 13 select 2 , 'カラム_1', 'A1' , '2020-01-02', '2020-01-01' 14insert into #table_a(TableID,xName,A_Number,日付_1,日付_2) 15 select 3 , 'カラム_1', 'A1' , '2020-01-03', '2020-01-01' 16insert into #table_a(TableID,xName,A_Number,日付_1,日付_2) 17 select 4 , 'カラム_1', 'A1' , '2020-01-04', '2020-01-01' 18 19 20-- ↑SQLの質問者はこの部分を提示してほしいマジで。 21-- 回答率めっちゃ上がるよ 22 23 24--最終形この形でよくない? 25select X.xName,X.A_Number,M1.日付_1,M1.TableID as ID_1,M2.日付_2,M2.TableID as ID_2 26from ( 27 select A.xName,A.A_Number 28 from #table_a as A 29 group by A.xName,A.A_Number 30) as X 31 outer apply ( 32 select top 1 M1.TableID,M1.日付_1 33 from #table_a as M1 34 where M1.xName=X.xName 35 and M1.A_Number=X.A_Number 36 order by M1.日付_1 desc 37 ) as M1 38 outer apply ( 39 select top 1 M2.TableID,M2.日付_2 40 from #table_a as M2 41 where M2.xName=X.xName 42 and M2.A_Number=X.A_Number 43 order by M2.日付_2 desc 44 ) as M2 45 46-- どうしてもっていうなら 47select X.xName,X.A_Number,Z.* 48from ( 49 select A.xName,A.A_Number 50 from #table_a as A 51 group by A.xName,A.A_Number 52) as X 53 outer apply ( 54 select top 1 M1.TableID,M1.日付_1 55 from #table_a as M1 56 where M1.xName=X.xName 57 and M1.A_Number=X.A_Number 58 order by M1.日付_1 desc 59 ) as M1 60 outer apply ( 61 select top 1 M2.TableID,M2.日付_2 62 from #table_a as M2 63 where M2.xName=X.xName 64 and M2.A_Number=X.A_Number 65 order by M2.日付_2 desc 66 ) as M2 67 cross apply ( 68 select M1.TableID as ID,M1.日付_1,null as 日付2 69 union all 70 select M2.TableID as ID,null,M2.日付_2 71 ) as Z 72order by Z.ID 73 74drop table #table_a 75 76

投稿2020/06/08 07:43

sousuke

総合スコア3830

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

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

ttt_xxx

2020/06/08 18:40

ご連絡遅くなりまして大変申し訳ございません。 これをみてハッとしました……! そうですね、勉強不足でした。 こちらのほうがきれいな形ですね。 申し訳ございません。 次また質問があったときは記載いただいたように詳しく記載しようかと思います。 ご教示いただきありがとうございました。
sousuke

2020/06/08 20:42

個人的に質問者の理想データをなにかに使う場合に、複数行または1行返却されたこのデータをみて「その行の日付1または日付2のどっちかまたは両方が最大である」という点までしかわからない点が致命的だと思います。
guest

0

ベストアンサー

SQL関数のGreatest()が使えると記述はもっと楽ですが、残念ながらSqlServerでは提供されません。
項目が多くなるとそれなりの記述になりますが、2項目の比較なら単に条件比較で良いでしょう。

SQL

1SELECT t1.* 2FROM table_a as t1 3 inner join ( 4 select name, A_number 5 , Max(case when 日付_1 > 日付_2 then 日付_1 else 日付_2 end) 最大日付 6 from table_a 7 group by name, A_number 8 ) as t2 9 ON t1.name = t2.name 10 AND t1.A_number = t2.a_number 11 AND case when t1.日付_1 > t1.日付_2 then t1.日付_1 else t1.日付_2 end=t2.最大日付

追記

ちょっと先走って回答になったので、訂正

SQL

1SELECT t1.* 2FROM table_a as t1 3where 日付_1 = (select max(日付_1) from table_a where name=t1.name and A_number=t1.A_number) 4 or 日付_2 = (select max(日付_2) from table_a where name=t1.name and A_number=t1.A_number)

投稿2020/06/08 04:58

編集2020/06/08 05:06
sazi

総合スコア25327

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

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

ttt_xxx

2020/06/08 18:26

ご連絡遅くなりまして大変申し訳ございません。 こ、これです!!! 無事に取得できました!!! ありがとうございました。 次また質問があったときは詳しく記載しようかと思います。 ご教示いただきありがとうございました。
guest

0

nameとA_numberでgorup byして日付1、2のmaxを取ればいいのでは?

投稿2020/06/08 03:47

yambejp

総合スコア116724

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

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

ttt_xxx

2020/06/08 04:20

ご回答いただきありがとうございます。 初歩的なことを申し上げてしまうのですが、JOINせずにということでしょうか?
yambejp

2020/06/08 04:28 編集

JOINは不要にみえます・・・ が、想定結果を見ましたが カラム_1、A1の日付1は最新は2020-01-02ですよね? これは日付2が2020-01-05のデータがあるので引きづられているのですか?
ttt_xxx

2020/06/08 04:52

申し訳ございません。たとえが悪くテーブルのデータを変更いたしました。 現状のデータとで申し上げますと、日付1の最新は2020-01-04なので、日付2の2020-01-01は最新ではありませんが、レコードが一緒のため結果に含まれる。 逆の日付2の最新は2020-01-05なので日付1は最新ではありませんが、レコードが一緒のため含まれる、といったものを想定しております。
yambejp

2020/06/08 05:03

あ、よく見たらid=3,4のデータ変更したのですね? これはデータがバリバリに競合しそうで難しい命題だと思います 日付1や日付2が最新のデータが1個しかない前提ですが、 他のデータを見るかぎり一つとは限らないですよね。 nameやnumber似関係なく日付1,日付2のデータが最新のものを もつものをそれぞれ抽出するということなら 以下のような感じになります
yambejp

2020/06/08 05:04

select * from tbl where 日付_1=(select max(日付_1) from tbl) or 日付_2=(select max(日付_2) from tbl)
ttt_xxx

2020/06/08 18:34

ご連絡遅くなりまして大変申し訳ございません。 無事に取得できました。 次また質問があったときは詳しく記載しようかと思います。 ご教示いただきありがとうございました。
guest

0

要件の再検討が必要です。

サブクエリで取得される日付_1と日付_2の最新日付は、同一のレコードである保証がありません。
実際、例示されているデータでは異なっている為、結果が表示されておりません。

必要なレコード(id)を取得する為の条件を整理してください。
例えば、日付_1>=日付_2なら日付_1、そうでないなら日付_2と結合。
他には、日付_1の最新日付のレコードと日付_2の最新日付のレコードで、最大のidとか。

追記
追加仕様を「日付_1>=日付_2なら日付_1、そうでないなら日付_2と結合」と仮定。

AND table_1.日付_1 = table_2.Date1_B AND table_1.日付_2 = table_2.Date2_B
AND ((table_2.Date1_B >= table_2.Date2_B AND table_1.日付_1 = table_2.Date1_B) OR (table_2.Date1_B < table_2.Date2_B AND table_1.日付_2 = table_2.Date2_B))

なお、テーブル構造が不明瞭なので、未検証です。

投稿2020/06/08 03:44

編集2020/06/08 04:58
YT0014

総合スコア1750

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

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

ttt_xxx

2020/06/08 04:35

ご回答ありがとうございます。 AND table_1.日付_1 = table_2.Date1_B AND table_1.日付_2 = table_2.Date2_B >> 実際、例示されているデータでは異なっている為、結果が表示されておりません。 ここの部分ですよね…… 取得したいレコード(SELECT結果)につきまして追記いたしました。 ※想定の結果(最終的に取得したい結果) こちらです。 もしお時間御座いましたらご確認よろしくお願いいたします。
YT0014

2020/06/08 04:45

表示された「最終的に取得したい結果」から推測するに、例に挙げた「日付_1>=日付_2なら日付_1、そうでないなら日付_2と結合」ですね。 依頼欄のsaziさんのコメント「日付1または日付2のうち大きい方での最大値」が正解で、良いでしょうか?
YT0014

2020/06/08 04:49

なお、結果だけ記載されても、仕様は、”推測”しかできません。プログラミングをされるのなら、仕様を、できるだけ正確に、網羅的に、提示できるように努力してください。 同時に、相手の提示した仕様を理解できるようにもなってください。
YT0014

2020/06/08 07:52 編集

yambejpさんの回答で気づきましたが、重複レコードがあった場合の仕様も検討する必要がありそうですね。 やはり、要件の再確認が必要かと。
ttt_xxx

2020/06/08 18:37

ご連絡遅くなりまして大変申し訳ございません。 最大値両方取得したかったのです。 申し訳ございません。 次回質問する際はもう少しきちんとまとめてからご質問させていただきます。 ご教示いただきありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問