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

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

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

Accessはマイクロソフトによるリレーショナルデータベース管理システムです。オブジェクト指向のアプリケーション作成に対応しており、テーブルや編集をはじめ、クエリ生成、入力フォーム作成、レポート作成など一通りの機能を備えています。

SQL

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

Q&A

解決済

4回答

6730閲覧

INSERT INTO と UNION ALL の Accessでの使い方について

t.mihiro

総合スコア0

Access

Accessはマイクロソフトによるリレーショナルデータベース管理システムです。オブジェクト指向のアプリケーション作成に対応しており、テーブルや編集をはじめ、クエリ生成、入力フォーム作成、レポート作成など一通りの機能を備えています。

SQL

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

0グッド

0クリップ

投稿2021/07/16 04:15

前提・実現したいこと

ExcelだったデータをAccessに移植した古いデータベースがあります。
ベースがExcelだったため、ピボットテールブルのような扱いをしており、
以下のような構造になっています。
ID 案件名 4月度売上 5月度売上 6月度売上
1  AAA   100    120    130
2  BBB   140    150    160
3  CCC    170    180    190


これをデータベースとして扱いやすいテーブル構造に変換するため、
1つの1年分のレコードを12分割し、以下のようなテーブルを作ろうと思っています。
ID 案件名 月度 売上
1 AAA 4月 100
2 AAA 5月 120
3 AAA 6月 130

13 BBB 4月 140
14 BBB 5月 150

しばらくは古いデータから定期的に新しいテーブルに
データを更新・インポートしたく、AccessのクエリをSQLで構築中なのですが
1カ月分のクエリは作れても、12カ月全部を一度に実行するクエリがうまく動作できません。
INSERT INTOとUNION ALLの組み合わせで、Access用の書き方が間違っているのかと思いますが、あまり例文も無く、躓いてしまいました。エラーが出ないようにするためには
どのようにSQLのクエリを記載すればよろしいでしょうか。

■1カ月分の追加クエリ(動作する)

INSERT INTO Newテーブル ( OldID, 案件名, 年度, 月度, 売上 ) SELECT [Oldテーブル].ID, [Oldテーブル].案件名, [Oldテーブル].年度, '4月', [Oldテーブル].[4月度売上] FROM Oldテーブル LEFT JOIN Newテーブル ON [Oldテーブル].ID = Newテーブル.OldID WHERE ([Oldテーブル].年度 >= 2021 AND NOT EXISTS (SELECT * FROM Newテーブル WHERE Newテーブル.OldID = Oldテーブル.ID));

■2カ月分の追加クエリ(動作しない)※本当は12カ月分やりたい

INSERT INTO Newテーブル ( OldID, 案件名, 年度, 月度, 売上 ) SELECT [Oldテーブル].ID, [Oldテーブル].案件名, [Oldテーブル].年度, '4月', [Oldテーブル].[4月度売上] FROM Oldテーブル LEFT JOIN Newテーブル ON [Oldテーブル].ID = Newテーブル.OldID WHERE ([Oldテーブル].年度 >= 2021 AND NOT EXISTS (SELECT * FROM Newテーブル WHERE Newテーブル.OldID = Oldテーブル.ID)) UNION ALL SELECT [Oldテーブル].ID, [Oldテーブル].案件名, [Oldテーブル].年度, '5月', [Oldテーブル].[5月度売上] FROM Oldテーブル LEFT JOIN Newテーブル ON [Oldテーブル].ID = Newテーブル.OldID WHERE ([Oldテーブル].年度 >= 2021 AND NOT EXISTS (SELECT * FROM Newテーブル WHERE Newテーブル.OldID = Oldテーブル.ID));

のように記述しましたが、エラーでクエリを保存できません。

発生している問題・エラーメッセージ

保存しようとすると以下のようなエラーが出ます。

クエリ式 '([Oldテーブル].年度 >= 2021 AND NOT EXISTS (SELECT * FROM Newテーブル WHERE Newテーブル.OldID = Oldテーブル.ID)) UNION ALL SELECT [Oldテーブル].ID, [Oldテーブル].案件名, [Oldテーブル].年度, '5月', [Oldテーブル].[5月度売上] FROM Oldテーブル LEFT JOIN Newテーブル ON [Oldテーブル].ID = Newテーブル.OldID WHERE ([Oldテーブル].年度 >= 2021 AND NOT EXISTS (SELECT * FROM Newテーブル WHERE Newテーブル.OldID = Oldテーブル.ID))'の 構文エラー:演算子がありません

試したこと

本来は、UpdateとRIGHT JOINで更新・追加を同時にしたいと思っていたのですが、
新しいデータベース側のSQL命令でRIGHT JOINが用意されてなく、
LEFT JOINしか対応しないために、更新しかできず追記がどうしても出来なかったため、
今は更新と追記を別々のクエリで作ってみています。

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

古いデータベースはAccessのデータベースで、新しいデータベースは
kintoneのデータベースをCData ODBC Driverでリンクテーブルとして読み込んでいます。

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

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

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

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

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

sazi

2021/07/17 23:39

> 新しいデータベース側のSQL命令でRIGHT JOINが用意されてなく 記述が誤っているだけでしょう。 > 更新しかできず追記がどうしても出来なかったため 更新のSQLも追記して下さい。
t.mihiro

2021/07/19 00:59 編集

記述が間違っている可能性は否定できません・・・ ただ、LEFT JOIN では動作するのにRIGHT JOINではエラーになるので、ドライバのリファレンスを見た所、LEFT JOINの記述はありましたが、RIGHT JOINの記述がなく、現在公式サポートに問い合わせ中です。
guest

回答4

0

他の方の回答にもあるようにユニオンクエリをサブクエリにする必要があると思います。
また、字数制限も気になりますので、ユニオンクエリを使わない方法を提案しておきます。

まず、下記のようなテーブルを作成します。

月度マスター

月度ID月度
14月
25月
36月

下記のSQLでユニオンクエリと同じ結果になります。SQLはかなりシンプルになります。(テーブルは一つ増えますが)

sql

1SELECT 2 Oldテーブル.ID AS OLdID, 3 Oldテーブル.案件名, 4 Oldテーブル.年度, 5 月度マスタ.月度, 6 Choose([月度ID], [4月度売上], [5月度売上], [6月度売上]) AS 売上 7FROM 8 Oldテーブル, 9 月度マスタ 10WHERE 11 Oldテーブル.年度=2021;

6月度までのSQLですが、同様にして3月度まで増やせばいいでしょう。


本来は、UpdateとRIGHT JOINで更新・追加を同時にしたいと思っていたのですが、

新しいデータベース側のSQL命令でRIGHT JOINが用意されてなく、
LEFT JOINしか対応しないために、更新しかできず追記がどうしても出来なかったため、
今は更新と追記を別々のクエリで作ってみています。

上記のSQLをQ1と名前をつけて保存して、下記のようなSQLで更新と追加が同時にできます。

sql

1UPDATE 2 Q1 LEFT JOIN Newテーブル 3 ON Q1.OLdID = Newテーブル.OldID 4SET 5 Newテーブル.OldID = [Q1].[OLdID], 6 Newテーブル.案件名 = [Q1].[案件名], 7 Newテーブル.年度 = [Q1].[年度], 8 Newテーブル.月度 = [Q1].[月度], 9 Newテーブル.売上 = [Q1].[売上];

クエリが2つになるのを避けたいなら、Q1をサブクエリにすれば一つのクエリにできます。

投稿2021/07/17 05:33

編集2021/07/17 07:03
hatena19

総合スコア33699

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

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

t.mihiro

2021/07/19 00:57

かなりシンプルになりますね。勉強になります。 こちらも試してみたいと思います。
t.mihiro

2021/07/19 09:27

おかげさまでChooseを利用してSQLを大幅にシンプルにする事ができ、やりたいことが実現できそうです。 ありがとうございました。
guest

0

UNION ALLの手前でINSERT文が完結されたとAccessが判断して
「演算子がありません」と出ているような・・・
UNION ALLするところ更にサブクエリにすれば実行出来ると思います。

SQL

1INSERT INTO Newテーブル ( OldID, 案件名, 年度, 月度, 売上 ) 2SELECT ID, 案件名, 年度, 月度, 売上 3FROM (SELECT 4 [Oldテーブル].ID 5 , [Oldテーブル].案件名 6 , [Oldテーブル].年度 7 , '4月' AS 月度 8 , [Oldテーブル].[4月度売上] AS 売上 9 FROM [Oldテーブル] 10 LEFT JOIN [Newテーブル] ON [Oldテーブル].ID = [Newテーブル].OldID 11 WHERE( 12 [Oldテーブル].年度 >= 2021 13 AND NOT EXISTS ( 14 SELECT * 15 FROM [Newテーブル] 16 WHERE [Newテーブル].OldID = [Oldテーブル].ID 17 ) 18 ) 19UNION ALL 20SELECT 21 [Oldテーブル].ID 22 , [Oldテーブル].案件名 23 , [Oldテーブル].年度 24 , '5月' 25 , [Oldテーブル].[5月度売上] 26 FROM [Oldテーブル] 27 LEFT JOIN [Newテーブル] ON [Oldテーブル].ID = [Newテーブル].OldID 28 WHERE( 29 [Oldテーブル].年度 >= 2021 30 AND NOT EXISTS ( 31 SELECT * 32 FROM [Newテーブル] 33 WHERE [Newテーブル].OldID = [Oldテーブル].ID 34 ) 35 ) 36) AS A;

一発のSQLで12ヶ月分やろうとすると、AccessのSQL文字数の制限に引っかかるかも知れません。
その場合はクエリを作ってクエリの入れ子状態にする必要があります。
(クエリの中のSQL文字数は文字数制限にはカウントされない仕様のようです)

投稿2021/07/16 14:12

odataiki

総合スコア938

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

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

t.mihiro

2021/07/19 00:56

なるほど、入れ子にして AS テーブル名でまとめるのですね。 やってみたいと思います。
guest

0

自己解決

皆様回答ありがとうございます。
とりあえずサブクエリで解決できました。

ただ、長いSQLなので、Chooseと別テーブルも時間のある時に検証したいと思います。
ありがとうございました!

動作したSQL抜粋は下記となります。

SQL

1INSERT INTO Newテーブル ( 案件名, FctID, エリア, 年度, 所課, クライアント名, 商材, 担当, 月度, 売上予測,) 2SELECT base.案件名, base.FctID, base.[エリア], base.年度, base.所課, base.[クライアント名], base.商材, base.担当, base.月度, base.売上予測, base.3FROM 4 (SELECT 案件名, ID as FctID, エリア, 年度, 支社 as 所課, クライアント名, 商材, 担当, '4月' as 月度, [4月Fct・売上] as 売上予測, 4 asFROM Oldテーブル 5UNION ALL 6 SELECT 案件名, ID as FctID, エリア, 年度, 支社 as 所課, クライアント名, 商材, 担当, '5月' as 月度, [5月Fct・売上] as 売上予測, 5 asFROM Oldテーブル 7UNION ALL 8 SELECT 案件名, ID as FctID, エリア, 年度, 支社 as 所課, クライアント名, 商材, 担当, '6月' as 月度, [6月Fct・売上] as 売上予測, 6 asFROM Oldテーブル 9) AS base 1011省略 1213WHERE NOT EXISTS (SELECT * FROM Newテーブル WHERE (Newテーブル.FctID = base.FctID AND Newテーブル.月度 = base.月度) );

[追記]

ご提示頂きましたChooseを使用した方法もRIGHT JOINと共に動作したので、
追加・更新が1つのクエリ対応できました。やはりRIGHT JOINに関しては記述に問題があったようです。
都度全部のデータを更新すると重たいので、今後は更新日時からデータを絞り込んで
実行しようかと思っております。
おかげさまでかなりシンプルなSQLになり大変助かりました。
皆様、ありがとうございました。

SQL

1UPDATE Newテーブル AS T1 2 RIGHT JOIN ( 3SELECT [Oldテーブル].案件名, 4 [Oldテーブル].ID AS FctID, 5 [Oldテーブル].[エリア], 6 [Oldテーブル].年度, 7 [Oldテーブル].支社 AS 所課, 8 [Oldテーブル].[クライアント名], 9 [Oldテーブル].商材, 10 [Oldテーブル].担当, 11 月度マスタ.月度, 12 Choose(月度マスタ.[月度ID], [3月Fct・売上], [4月Fct・売上], [5月Fct・売上], [6月Fct・売上], [7月Fct・売上], [8月Fct・売上], [9月Fct・売上], [10月Fct・売上], [11月Fct・売上], [12月Fct・売上], [1月Fct・売上], [2月Fct・売上] ) AS 売上予測, 13 Choose(月度マスタ.[月度ID], 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2 ) AS, 14 [Oldテーブル].[データ更新日時] AS 更新日時 15 FROM Oldテーブル, 月度マスタ ORDER BY [Oldテーブル].ID) AS base 16 ON (T1.月度 = base.月度) AND (T1.FctID = base.FctID) 17 SET 18 T1.FctID = base.FctID, 19 T1.年度 = base.年度, 20 T1.月度 = base.月度, 21 T1.= base., 22 T1.案件名 = base.案件名, 23 T1.クライアント名 = base.[クライアント名], 24 T1.エリア = base.[エリア], 25 T1.商材 = base.商材, 26 T1.担当 = base.担当, 27 T1.所課 = base.所課, 28 T1.売上予測 = base.売上予測, 29 T1.更新日時 = base.更新日時 30;

投稿2021/07/19 01:12

編集2021/07/19 09:25
t.mihiro

総合スコア0

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

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

sazi

2021/07/19 01:54

各unionで該当月の売上の有無は判定しなくて良いのですか? ※例えば、今年度中で到来していない月の分とか。 データが無くても追加するなら、新しいテーブルに処理を変更する際には必ず12か月分のデータを入れておくなどの考慮が必要になると思います。
t.mihiro

2021/07/19 09:16

今は古いDBシステムからの移行準備で定期的にデータを更新させるので、一定時間ごとに更新できればと思っております。ありがとうございます。
sazi

2021/07/19 10:20

Newテーブルを更新するんだからright joinは意味がありませんね。 実行時間を考えると inner joinの方が良いと思います。 ※サブクエリー内のORDER BYも不要ですね。
guest

0

IIf()を駆使したらカラムの参照先の読み替えもシンプルにできそう。

IIf(~="4月",[Oldテーブル].[4月度売上],IIf(~="5月",[Oldテーブル].[5月度売上],IIf(~="6月",[Oldテーブル].[6月度売上],・・・・・・)))

投稿2021/07/16 04:35

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

t.mihiro

2021/07/16 09:42

古いテーブルは1レコードにを12カ月分のデータが入っているので、 IIFでは出来ない気がするのですが・・・ 新しいテーブルから古いテーブルへの逆方向なら 月をIIFで分岐させれば、データを入れ込むカラムを指定できると思います。 1個のレコードを12個のレコードに分解させる必要があるので、 12カ月分 UNION ALL して読み込ませる必要があるのではないかと思うのですが、 それがうまくいかずに困っております。そもそも1回のクエリで12個に分ける方法があれば良いのですが・・・
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問