以前投稿したのですが、抽出するテーブルに問題があり、
再度投稿させて頂きます。
SQLを使うのが初心者なので勉強をしながら作業を行なっています。そのため説明不足などありましたらご指摘願います。
[環境]
データベース:SQLServer2005
質問内容は、
会員マスタテーブル
会員CD,会員住所,SHIMEI,KOSHINDAY
0001,東京,太郎,20090101
0001,千葉,太郎,20090102
0002,東京,次郎,20090101
0002,大阪,次郎,20090109
0003,大阪,三郎,20090109
0003,奈良,三郎,20090110
0004,大阪,四郎,20090109
代理人テーブル
会員CD,代理人CD,業務CD,KOSHINDAY
0001,0002,15,20090101
0001,0003,15,20090102
0002,0001,01,20090201
0002,0004,10,20090202
0003,0001,10,20090201
0003,0004,15,20090202
上記のようなテーブルがあります。
抽出結果ですが、
会員CD,会員住所,SHIMEI,KOSHINDAY,代理人CD,代理人住所,代理人名...
0001,千葉,太郎,20090102,0003,奈良,三郎,20090110
0002,大阪,次郎,20090109
0003,奈良,三郎,20090110,0004,大阪,四郎,20090109
会員マスタテーブルにて、各会員のKOSHINDAYが最大のデータを抽出します。
会員マスタテーブルの会員CDを元に、代理人テーブルを検索し各々KOSHINDAYが最大の代理人CDを求め、その時に業務CD=15のものだけを選び、
選び出された代理人CDで、会員マスタテーブルを検索し、
代理人の住所・氏名を抽出します。
上記内容なのですが、一回のSQL文で抽出が可能でしょうか?
仮想的にアクセスで検証したのですが、
作成出来ませんでした、すいませんが宜しくお願いします。
No.5ベストアンサー
- 回答日時:
>エイリアスをA・B・Cと付けた場合に、次のエラー表示がされるのですが、どのような対処をすれば宜しいのでしょう。
>ちなみにA・B・Cをそれぞれのテーブル名
>A=会員マスタテーブル B=代理人テーブルとした場合は、エラーになりません。
クエリの後ろのエイリアスだけ変更して、「ON」の後ろの結合条件を変更しなかったときには、そのようなメッセージが出ます。
たとえば、こんな感じに
LEFT OUTER JOIN
(SELECT * FROM 代理人テーブル b1
WHERE b1.KOSHINDAY IN
(SELECT MAX(KOSHINDAY) FROM 代理人テーブル WHERE 会員CD=b1.会員CD)) b
ON 代理人テーブル.会員CD=会員マスタテーブル.会員CD
気をつけていただきたいのは、クエリは階層になっているわけですので、最終的なSELECT文はもはやクエリの結果を返すのに
会員マスタテーブルや代理人テーブルを直接は参照しておらず、あくまでも3つのクエリの結果(a,b,c)だけを使っているという点です。
従って、結合にはa,b,cだけを使うことができます。
>会員テーブルの更新日で(MAX関数)による抽出に対しては、1会員1行になる事は、確認済みです。
私が#2で書いたクエリは、
SELECT * FROM 会員マスタテーブル a1
WHERE a1.KOSHINDAY IN
(SELECT MAX(KOSHINDAY) FROM 会員マスタテーブル WHERE 会員CD=a1.会員CD)
SELECT * FROM 代理人テーブル b1
WHERE b1.KOSHINDAY IN
(SELECT MAX(KOSHINDAY) FROM 代理人テーブル WHERE 会員CD=b1.会員CD)
この上記2つのクエリ結果が常に1会員1行になるのであれば、会員CDでの重複は絶対に発生しません。
実際の環境に合わせてどのように書き換えられたかわかりませんので、そこをチェックしていただきたいです。
やっと出来ました、ありがとうございました。
問題であった重複データが存在した件ですが、
3つのクエリを分割して流した所、
2つ目のクエリで代理人テーブルにてKOSHINDAYが一人の会員に対して重複してました。
理由としては、代理人を登録する際に、業務CDを複数登録出来る為に
KOSHINDAYが同日で業務CDが違うレコードが一人の会員に対して複数存在しました。
その為、他の項目にて重複しないようWHERE文を追加し
3つ目のクエリで聴いている、業務CD = '15' の問い合わせを
2つ目のクエリに追加しました。
こんな感じです。
(SELECT * FROM 代理人テーブル B1
WHERE B1.KOSHINDAY IN
(SELECT MAX(KOSHINDAY) FROM 代理人テーブル WHERE 会員CD = B1.会員CD)
AND GYOMUCD = '15' AND 終了日 = '999999') B ON B.会員CD = A.会員CD
大変お世話になりました。
又、不明な点がありましたら宜しくお願いします。
No.6
- 回答日時:
#3回答者です。
jamshid6さんとのやり取りで解決できたとのことで、まずはよかったですね。
質問&回答の横から入るような形になりましたが、「分析関数」や「WITH句による共通表式」(SQL Serverでは、再帰クエリも可)は非常に便利な機能なので、ぜひ勉強してみてください。
また、#3で示したように、CREATE TABLE文やINSERT文を貼り付けて、アドバイスしようとする側ですぐに利用できるようにしてもらえれば、より多くの人が、より効率的にアドバイスできるので、早く適切なアドバイスが得られる可能性があります。
No.4
- 回答日時:
今回のケースで、会員番号が重複する理由はおそらく、質問者さんの会員テーブルの主キーが会員CD、更新日になっていないことによります。
つまり、更新日が最新のものを取るようにしても、1会員1行にならないということです。
(同じ日に同じ会員の情報を2回3回と更新したときにそのテーブルはどうなりますか?)
SELECT * FROM 会員マスタテーブル a1
WHERE a1.KOSHINDAY IN
(SELECT MAX(KOSHINDAY) FROM 会員マスタテーブル WHERE 会員CD = a1.会員CD)
は、「会員マスタテーブルからそれぞれ更新日が最新のものだけを抽出した結果」を示し、本来この時点で1会員1行になっていなければだめです。
(同じことは代理人テーブルに関しても言えます)
#3の方が書かれている方法は、「会員単位に更新履歴の降順に並べ替えて先頭の1行を取る」という方法です。
その方法を使えば必ず1会員1行になりますが、同じ更新日で2件以上入っていればどちらが新しいかもわかりませんよね?
更新履歴をすべてマスタが持っているのであれば、必ず最新のデータが特定できるような構造にしておかないといけません(更新順に連番を振るなど)。
その上で、理解していただくために質問にコメントしますが、
>括弧の後に記述するテーブル名は、どのような役割をするのでしょうか?
括弧の後に記述しているのは、テーブル名ではなく、エイリアス(別名)といいます。
テーブル名の後につけた場合は、そのテーブル名を示しますので、クエリ内で何度もテーブル名を書かなくてよくなります。
今回のように括弧(1つのクエリを括弧で括ったもの)の後につけると、そのクエリの結果に対する別名として使われます。
言いかえると、括弧内のクエリが返す結果をバーチャルなテーブルとみなして使うということです。
(インラインビューと呼んだりします)
また、別名を使うことで、同じテーブルや同じクエリを複数回結合に使うこともできるようになります。aとcは全く同じクエリの結果を結合に使っていますが、別名をつけているので、それぞれ別物として取り扱われます。
この回答への補足
お忙しい中、回答を頂きありがとうございました。
自分で考えたSQLなどを提示し、不明点を具体的に示すことがルールです。←すいませんでした。以後気を付けます。
先程のご指摘の件ですが、
会員テーブルの更新日で(MAX関数)による抽出に対しては、
1会員1行になる事は、確認済みです。
苦言を言われるかもしれませんが、質問します。
エイリアスをA・B・Cと付けた場合に、次のエラー表示がされるのですが、どのような対処をすれば宜しいのでしょう。
ちなみにA・B・Cをそれぞれのテーブル名
A=会員マスタテーブル B=代理人テーブルとした場合は、エラーになりません。
メッセージ 4104、レベル 16、状態 1、行 1
マルチパート識別子 "会員マスタテーブル.会員CD" をバインドできませんでした。
以上です。宜しくお願いします。
No.3
- 回答日時:
まず、苦言から。
ここは、「仕様を提示して、SQLなどを作ってもらう」サイトではありません。
自分で考えたSQLなどを提示し、不明点を具体的に示すことがルールです。
SQL Server 2005とのことなので、今回のようなケースで活用できる機能が実装されています。
(1)Oracleでいう「分析関数」
特定の列値でグループ化し、最大値あるいは最小値を持つ行の全列を得たいといったことが容易になります。
(2)WITH句による共通表式
同じクエリを繰り返し使いたい場合に、ビュー表などを事前に定義したり、同じクエリを何度も書かなくてもよくなります。
1.SQL例
1.1 準備
(1)必要なら表を削除
drop table ktbl;
drop table dtbl;
(2)表の定義
create table ktbl
(kcd char(4),
kaddr varchar(10),
shimei varchar(10),
koshinday char(8));
create table dtbl
(kcd char(4),
dcd char(4),
gcd char(2),
koshinday char(8));
(3)テスト用のデータ
insert into ktbl values('0001','東京','太郎','20090101');
insert into ktbl values('0001','千葉','太郎','20090102');
insert into ktbl values('0002','東京','次郎','20090101');
insert into ktbl values('0002','大阪','次郎','20090109');
insert into ktbl values('0003','大阪','三郎','20090109');
insert into ktbl values('0003','奈良','三郎','20090110');
insert into ktbl values('0004','大阪','四郎','20090109');
insert into dtbl values('0001','0002','15','20090101');
insert into dtbl values('0001','0003','15','20090102');
insert into dtbl values('0002','0001','01','20090201');
insert into dtbl values('0002','0004','10','20090202');
insert into dtbl values('0003','0001','10','20090201');
insert into dtbl values('0003','0004','15','20090202');
2.検索
with
kq(kcd,kaddr,shimei,koshinday)
as
(select
kcd,kaddr,shimei,koshinday
from(select *,row_number() over(partition by kcd order by koshinday desc) as rn
from ktbl) as x
where x.rn=1),
dq(kcd,dcd,gcd,koshinday)
as
(select
kcd,dcd,gcd,koshinday
from(select *,row_number() over(partition by kcd order by koshinday desc) as rn
from dtbl
where gcd='15') as y
where y.rn=1)
select
kq1.kcd as "会員CD",
kq1.kaddr as "会員住所",
kq1.shimei as "会員氏名",
kq1.koshinday as "会員更新日",
kq2.kcd as "代理人CD",
kq2.kaddr as "代理人住所",
kq2.shimei as "代理人氏名",
kq2.koshinday as "代理人更新日"
from kq as kq1
left join dq on kq1.kcd=dq.kcd
left join kq as kq2 on dq.dcd=kq2.kcd
order by kq1.kcd
;
No.2
- 回答日時:
>会員マスタテーブルの各々KOSHINDAYがMAXデータは、すべて必要です。
普通にやればそうなるので、結果を4行書いておいてくれれば、余計なことは考えなかったんですけどね。
それから、見ての通り、クエリはほとんど違いません。
(つまりほとんどすべてのポイントが含まれていたということです)
前のクエリから導けるようになるといいですね。
SELECT
a.会員CD,
a.会員住所,
a.SHIMEI,
a.KOSHINDAY,
c.会員CD 代理人CD,
c.会員住所 代理人住所,
c.SHIMEI 代理人名,
c.KOSHINDAY
FROM
(SELECT * FROM 会員マスタテーブル a1
WHERE a1.KOSHINDAY IN
(SELECT MAX(KOSHINDAY) FROM 会員マスタテーブル WHERE 会員CD=a1.会員CD)) a
LEFT OUTER JOIN
(SELECT * FROM 代理人テーブル b1
WHERE b1.KOSHINDAY IN
(SELECT MAX(KOSHINDAY) FROM 代理人テーブル WHERE 会員CD=b1.会員CD)) b
ON b.会員CD=a.会員CD
LEFT OUTER JOIN
(SELECT * FROM 会員マスタテーブル c1
WHERE c1.KOSHINDAY IN
(SELECT MAX(KOSHINDAY) FROM 会員マスタテーブル WHERE 会員CD=c1.会員CD)) c
ON c.会員CD=b.代理人CD AND b.業務CD='15'
ORDER BY 1
この回答への補足
回答頂いた内容で、処理してみたのですが、
会員CDが重複してしまい抽出件数が膨大になってしまいました。
そこで、確認なのですが、括弧で括られたSELECT文の後に、a b c
とありますが、これは、a = 会員マスタテーブル b = 代納人テーブルだと思うのですが、
cについては、どうなるのでしょうか?
会員マスタテーブル AS c ということなのでしょうか?
正確な記述をFROM~すると
FROM
(SELECT * FROM 会員マスタテーブル a1
WHERE a1.KOSHINDAY IN
(SELECT MAX(KOSHINDAY) FROM 会員マスタテーブル WHERE 会員CD = a1.会員CD)) 会員マスタテーブル ←括弧の後に
記述するテーブル名は、
どのような役割をするのでしょうか?
LEFT OUTER JOIN
(SELECT * FROM 代理人テーブル b1
WHERE b1.KOSHINDAY IN
(SELECT MAX(KOSHINDAY) FROM 代理人テーブル WHERE 会員CD = b1.会員CD)) 代理人テーブル
ON 代理人テーブル.会員CD = 会員マスタテーブル.会員CD
LEFT OUTER JOIN
(SELECT * FROM 会員マスタテーブル c1
WHERE c1.KOSHINDAY IN
(SELECT MAX(KOSHINDAY) FROM 会員マスタテーブル WHERE 会員CD = c1.会員CD)) c←不明です。
ON 会員マスタテーブル.会員CD = 代理人テーブル.代理人CD AND 代理人テーブル.業務CD = '15'
ORDER BY 会員マスタテーブル.会員CD
以上です。このような記述でよろしいのでしょうか?
お忙しい所、申し訳ございませんがよろしくお願いします。
No.1
- 回答日時:
結果をみる限り、業務CDに関わらず代理人がいる会員だけが対象のようですね。
したがって、メインのテーブルは代理人テーブルとし、以下のようにつなぎます。
SELECT
a.会員CD,
b.会員住所,
b.SHIMEI,
b.KOSHINDAY,
c.会員CD 代理人CD,
c.会員住所 代理人住所,
c.SHIMEI 代理人名,
c.KOSHINDAY
FROM
(SELECT * FROM 代理人テーブル a1
WHERE a1.KOSHINDAY IN
(SELECT MAX(KOSHINDAY) FROM 代理人テーブル WHERE 会員CD=a1.会員CD)) a
LEFT OUTER JOIN
(SELECT * FROM 会員マスタテーブル b1
WHERE b1.KOSHINDAY IN
(SELECT MAX(KOSHINDAY) FROM 会員マスタテーブル WHERE 会員CD=b1.会員CD)) b
ON b.会員CD=a.会員CD
LEFT OUTER JOIN
(SELECT * FROM 会員マスタテーブル c1
WHERE c1.KOSHINDAY IN
(SELECT MAX(KOSHINDAY) FROM 会員マスタテーブル WHERE 会員CD=c1.会員CD)) c
ON c.会員CD=a.代理人CD AND a.業務CD='15'
ORDER BY 1
この回答への補足
素早い解答ありがとうございます。
せっかくの解答なのでが、忘れていました。
会員マスタテーブルの各々KOSHINDAYがMAXデータは、すべて必要です。
その中には、代理人テーブルに会員CDを持たない人も存在しますが
代理人が居ない会員は、代理人の住所等は、NULLでOKなのです。
すいませんが宜しくお願いします。
こんな感じです。
会員CD,会員住所,SHIMEI,KOSHINDAY,代理人CD,代理人住所,代理人名...
0001,千葉,太郎,20090102,0003,奈良,三郎,20090110
0002,大阪,次郎,20090109
0003,奈良,三郎,20090110,0004,大阪,四郎,20090109
0004,大阪,四郎,20090109
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- SQL Server AccessのInsertクエリのあとつづけてDeleteクエリを行いたいがSQLでどう書いたらいい 3 2023/05/27 14:12
- 公認会計士・税理士 申告書等の税理士欄について 5 2022/09/14 17:23
- 心理学 太郎君を助けてあげてください。(長文です) 3 2022/11/20 15:56
- 外国株 松井証券に証券取引口座をもつが 1 KO コカ コーラが先週取引ランキング トップ10にない、米国株 1 2022/08/10 13:57
- 政治 次の愛国心あった田中派・経世会と売国心しかない清和会の全く真逆の違いをどう思いまっか? 1 2023/05/28 20:38
- PostgreSQL PostgreSQL レコードからアイテム種類数を取得したい 2 2022/11/23 22:31
- その他(Microsoft Office) Outlookメール 連絡先の検索について 〈 ご説明 〉 Windows PC の Outlook 1 2022/09/23 14:43
- 政治 水道橋博士と松井一郎の争い、皆さんどう思いますか? ・ツイッターでのリツイート行為を訴えた松井。 ・ 4 2022/11/02 17:56
- クラシック どっちが上か?第二弾「葉加瀬太郎と高嶋ちさ子、どっちを選ぶ? 究極の選択」 7 2023/05/08 19:49
- Oracle sqlで質問です。 idを元にidに紐付くデータで住所コードがjpのみのデータ以外のidを取得したい 4 2023/03/20 17:41
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ビューで引数を使いたい
-
ACCESS 一番最新の日付の金額...
-
IFで条件を分岐させてのINSERT...
-
Accessで在庫管理を
-
INSERT文でサブクエリ
-
二つの表の項目を比較して値を...
-
DB2 業種毎に連番をつけたいの...
-
年齢分布テーブルの再集計SQL
-
「マスタ」と「テーブル」の違...
-
ACCESSのSQLで、NULLかNULLでな...
-
数百万件レコードのdelete
-
[ BETWEEN ] vs [ >= AND <= ]
-
ACCESS2007 フォーム 「バリア...
-
3つ以上のテーブルをUNIONする...
-
Access VBA [リモートサーバー...
-
sqlserverで集計結果をUPDATEし...
-
SELECT時の行ロックの必要性に...
-
2つの項目が重複するレコード...
-
重複するキーから一番古い年月...
-
accessテーブル作成クエリを実...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
ACCESS 一番最新の日付の金額...
-
ビューで引数を使いたい
-
IFで条件を分岐させてのINSERT...
-
大学でSQLの授業があるのですが...
-
二つの表の項目を比較して値を...
-
Accessで在庫管理を
-
SQLについて質問です。 テーブ...
-
SQL 件数取得を速くしたい
-
複数のテーブルから同じ条件で...
-
空のテーブルの判別
-
INSERT文でサブクエリ
-
SQLの書き方
-
DB2 業種毎に連番をつけたいの...
-
Insert Into Select での重複に...
-
Access関数について クエリで空...
-
SQLで○○の値以外を持っているレ...
-
Sql文のUpdateと副問い合わせで...
-
select into句のトランザクショ...
-
リレーションシップ 全データを...
-
条件が混在しているSQLで値取得
おすすめ情報