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

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

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

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

2回答

1833閲覧

複数で、階層を持ったテーブルのjoinがうまくいかない。

退会済みユーザー

退会済みユーザー

総合スコア0

SQL Server

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

1クリップ

投稿2019/06/11 01:27

編集2019/06/12 04:40

◎テーブルの説明

SQL

1create table ユーザー( 2 ユーザーCD varchar(12) PRIMARY KEY, 3 氏名 varchar(40) not NULL, 4 電話番号 varchar(20) not NULL 5); 6 7create table 商品( 8 商品No varchar(11) PRIMARY KEY, 9 ユーザーCD varchar(12) , 10 購入日 datetime 11); 12 13create table 識別( 14 識別No varchar(20) PRIMARY KEY, 15 商品CD varchar(7) , 16 商品No varchar(11) 17); 18 19create table 定期( 20 定期No varchar(12) PRIMARY KEY, 21 ユーザーCD varchar(12) 22); 23 24create table 定期商品( 25 定期No varchar(12) PRIMARY KEY, 26 定期商品No int not NULL, 27 商品No varchar(11) 28); 29 30create table 定期履歴( 31 定期No varchar(12) PRIMARY KEY, 32 定期履歴連番 int not NULL, 33 解約フラグ int, 34 定期開始日 datetime, 35 定期終了日 datetime 36);

SQL

1insert into ユーザー values ('100000000001','テスト太郎1','09011112222'); 2insert into ユーザー values ('100000000002','テスト太郎2','09111112222'); 3 4insert into 商品 values ('11111111111','100000000001','2018-12-11'); 5insert into 商品 values ('11111111112','100000000002','2018-12-12'); 6 7insert into 識別 values ('12345678901234567890','MKN1111','11111111111'); 8insert into 識別 values ('12345678901234567891','MKN1111','11111111111'); 9insert into 識別 values ('12345678901234567892','MKN1111','11111111112'); 10 11insert into 定期 values ('555555555555','100000000001'); 12 13insert into 定期商品 values ('555555555555','1','11111111111'); 14 15insert into 定期履歴 values ('555555555555','1','0','2016/1/1','2016/12/31'); 16insert into 定期履歴 values ('555555555555','2','0','2017/1/1','2017/12/31'); 17insert into 定期履歴 values ('555555555555','3','0','2018/1/1','2018/12/31'); 18insert into 定期履歴 values ('555555555555','4','0','2019/1/1','2019/12/31');

※テスト太郎1の持つ商品に付いている定期は、定期終了日が2019/12/31で解約フラグ0なので有効な定期がある。
定期履歴連番3で止まっていたり、定期履歴連番4があっても解約フラグ1なら定期が切れている。
また、テスト太郎2の持つ商品には定期が付いていない。

※「定期履歴」テーブルは「定期」テーブルの下の階層。

定期No、定期履歴連番、定期開始日、定期終了日
1,1,2016/1/1,2016/12/31
1,2,2017/1/1,2017/12/31
1,3,2018/1/1,2018/12/31
1,4,2019/1/1,2019/12/31

◎やりたい抽出
商品を持つユーザーについて、「定期」が無いか、切れているユーザーを抽出したい。

「定期」が無いとは・・・そのユーザーについて「定期」テーブルのデータが無い。
「定期」が切れているとは・・・「定期履歴」の解約フラグが1、または定期終了日がシステム日付を過ぎている。

◎途中経過

複雑な構造なので、joinするとユーザがタブったりします。
しかも、「定期履歴」テーブルについては定期履歴連番がMAXのデータを見る必要があります。
例でいうと、連番4の2019/1/1~2019/12/31定期のデータでみたい。

SQL

1select * 2from [商品] 3INNER JOIN [ユーザー] on [ユーザー].[ユーザーCD] = [商品].[ユーザーCD] 4INNER JOIN [識別] on [識別].[定期No] = [商品].[定期No] 5LEFT JOIN [定期] on [定期].[ユーザーCD] = [ユーザー].[ユーザーCD] 6LEFT JOIN [定期商品] on [商品].[定期No] = [定期商品].[定期No] 7INNER JOIN [定期履歴] on [定期履歴].[定期No] = [定期].[定期No] 8 9WHERE 10 11AND ([定期終了日] < 'システム日付' OR [解約フラグ]=1 or [定期].[定期No] IS NULL ) 12AND [定期履歴連番] = (SELECT MAX([定期履歴連番]) from [定期履歴] WHERE [定期].[定期No] = [定期履歴].[定期No]

結合のキーが足りないのか、LEFT JOINの使い方が違うのか、なかなかうまくいきません。
うまくいく方法が分かりましたら、教えていただけないでしょうか。
よろしくお願いします。

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

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

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

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

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

yambejp

2019/06/11 01:31

複雑な検証を希望する場合はcreate table/insertでサンプルを付けてください
Orlofsky

2019/06/11 01:35

質問のテーブルの定義情報は、できれば CREATE TABLE に、テーブルに存在するデータをINSERT文で https://teratail.com/help#about-markdown の[コードを入力] で載せると適切な回答が付き易いです。
退会済みユーザー

退会済みユーザー

2019/06/11 02:14

補足に回答いたしました、よろしくお願いします。
Orlofsky

2019/06/11 02:34

質問を ```SQL CREATE TABLE ... ``` ```SQL INSERT ... ``` に修正してください。 少しは他の人の質問も見て書き方を理解してください。
退会済みユーザー

退会済みユーザー

2019/06/11 02:52

大変申し訳ありませんでした。対応しました。
Orlofsky

2019/06/11 09:36

PRIMARY KEYはCREATE TABLEに追加、 ; は省略しない。 >に修正してください。 と書いたように、最初のテーブル定義は不要だから削除。 SELECTもコードだから、 https://teratail.com/help#about-markdown の[コードを入力] に修正。 > SQL Server 入門 で一通り勉強しないと実務に入れませんよ。
退会済みユーザー

退会済みユーザー

2019/06/12 00:43

修正しました。ご指摘ありがとうございました。
Orlofsky

2019/06/12 04:21

CREATE TABLEでPRIMARY KEY に複数のカラムがあるとエラーになりますよね? セミコロンも抜けたままだし。
退会済みユーザー

退会済みユーザー

2019/06/12 04:40

何度も申し訳ありません。
Orlofsky

2019/06/12 05:14

掲示版に載せる前にSQL(今回は CREATE TABLEと INSERT) を実行してエラーにならないか確認してください。 >SQL Server PRIMARY KEY 複数 でググってもいないですし。
guest

回答2

0

ベストアンサー

結局どんな商品について定期を持たないのかの識別も必要になるでしょうし、商品を抽出するようにしてみました。
ユーザーが必要であれば、商品のユーザーCDから取得できますしね。

SQL

1select * 2from 商品 3where not exists ( 4 select 1 5 from 定期 6 inner join 定期履歴 on 定期.定期No=定期履歴.定期No 7 inner join 定期商品 on 定期.定期No=定期商品.定期No 8 where 定期履歴連番=( 9 select max(定期履歴連番) from 定期履歴 hst where 定期No=定期履歴.定期No 10 ) 11 and 定期終了日 > getdate() and 解約フラグ=0 12 and 定期商品.商品No=商品.商品No and 定期.ユーザーCD=商品.ユーザーCD 13 )

投稿2019/06/11 03:10

sazi

総合スコア25184

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

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

退会済みユーザー

退会済みユーザー

2019/06/11 06:40

クエリをご提供いただきありがとうございました。ぜひ参考にさせていただきます。
guest

0

MAXを見る必要ありますかね?

SQL

1SELECT * FROM ユーザー U 2WHERE 3-- 商品を持つ 4EXISTS (SELECT * FROM 商品 I WHERE I.ユーザーCD = U.ユーザーCD) 5-- 定期がない 6AND NOT EXISTS ( 7 SELECT * FROM 定期履歴 H 8 INNER JOIN 定期 T ON T.定期No = H.定期No 9 WHERE H.解約フラグ <> 1 AND H.定期終了日 >= GETDATE() 10 AND T.ユーザーCD = U.ユーザーCD 11)

投稿2019/06/11 02:29

x_x

総合スコア13749

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

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

退会済みユーザー

退会済みユーザー

2019/06/11 06:40

クエリをご提供いただきありがとうございました。ぜひ参考にさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問