C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

レコードをコピーしてキーコードを変える

[トピック内 14 記事 (1 - 14 表示)]  << 0 >>

■93562 / inTopicNo.1)  レコードをコピーしてキーコードを変える
  
□投稿者/ たかし (38回)-(2019/12/22(Sun) 12:30:03)

分類:[データベース全般] 

毎度お世話になっております、たかしです。
SQLについて教えて下さい。
テーブルAの既存のレコードを同じテーブルの新規行にコピーしたいと思い、次のようなSQL文を書きました。

INSERT INTO テーブルA(主キー, フィールド1, フィールド1, フィールド1・・・)
SELECT 主キー, フィールド1, フィールド1, フィールド1・・・
FROM テーブルA
WHERE 主キー = @主キー

しかし、同じテーブルであるため当然のことながら「主キー」がダブってしまいエラーとなってしまいます。
主キーがダブらないように、新規行に(最終主キー値+1)を設定するうまい方法はないものでしょうか?

引用返信 編集キー/
■93563 / inTopicNo.2)  Re[1]: レコードをコピーしてキーコードを変える
□投稿者/ WebSurfer (1997回)-(2019/12/22(Sun) 13:23:23)
No93562 (たかし さん) に返信

SQL のことを聞くなら DB サーバーは何か書きましょう。DB サーバーによって
方言のようなものがあって少しづつ異なります。
引用返信 編集キー/
■93565 / inTopicNo.3)  Re[2]: レコードをコピーしてキーコードを変える
□投稿者/ たかし (39回)-(2019/12/22(Sun) 16:30:53)
No93563 (WebSurfer さん) に返信
> ■No93562 (たかし さん) に返信
>
> SQL のことを聞くなら DB サーバーは何か書きましょう。DB サーバーによって
> 方言のようなものがあって少しづつ異なります。

はいすみません。
SQLサーバーです。


引用返信 編集キー/
■93566 / inTopicNo.4)  Re[3]: レコードをコピーしてキーコードを変える
□投稿者/ WebSurfer (1998回)-(2019/12/22(Sun) 18:25:24)
No93565 (たかし さん) に返信

+1 してもそれがダブらないという保証はないのでは?

Identity にして採番は SQL Server に任せてはいかがですか。ほかによい解決策は
なさそうな気がします。
引用返信 編集キー/
■93574 / inTopicNo.5)  Re[3]: レコードをコピーしてキーコードを変える
□投稿者/ kiku (158回)-(2019/12/23(Mon) 11:56:34)
No93565 (たかし さん) に返信
> ■No93563 (WebSurfer さん) に返信
>>■No93562 (たかし さん) に返信
>>
>>SQL のことを聞くなら DB サーバーは何か書きましょう。DB サーバーによって
>>方言のようなものがあって少しづつ異なります。
>
> はいすみません。
> SQLサーバーです。

下記みたいに、主キーの最大値+1で上書きではどうでしょう?

https://pumpkin.hatenablog.jp/entry/20080121/1200934115

MAXのところを変更すれば、質問者さんの思った通りに
主キー+1にすることもできます。

引用返信 編集キー/
■93578 / inTopicNo.6)  Re[4]: レコードをコピーしてキーコードを変える
□投稿者/ たかし (40回)-(2019/12/23(Mon) 19:28:40)
No93574 (kiku さん) に返信
> ■No93565 (たかし さん) に返信
>>■No93563 (WebSurfer さん) に返信
> >>■No93562 (たかし さん) に返信
> >>
> >>SQL のことを聞くなら DB サーバーは何か書きましょう。DB サーバーによって
> >>方言のようなものがあって少しづつ異なります。
>>
>>はいすみません。
>>SQLサーバーです。
>
> 下記みたいに、主キーの最大値+1で上書きではどうでしょう?
>
> https://pumpkin.hatenablog.jp/entry/20080121/1200934115
>
> MAXのところを変更すれば、質問者さんの思った通りに
> 主キー+1にすることもできます。
>

kiku様、ありがとうございます。
ご紹介いただいたページを参考に、

INSERT INTO テーブルA(主キー, フィールド1, フィールド1, フィールド1・・・)
SELECT MAX(主キー) + 1, フィールド1, フィールド1, フィールド1・・・
FROM テーブルA
WHERE 主キー = @主キー

以上のようなストアドプロシージャを書いてみましたが、実行の段階でエラーとなり進むことができません。
結局、VB側でフォームからフォームにデータをコピーして更新させるというめんどくさい方法で、
なんとかやろうとしていたことができました。
皆さんありがとうございました。



解決済み
引用返信 編集キー/
■93579 / inTopicNo.7)  Re[5]: レコードをコピーしてキーコードを変える
□投稿者/ 魔界の仮面弁士 (2535回)-(2019/12/23(Mon) 19:53:25)
No93578 (たかし さん) に返信
>>> SQLサーバーです。
だったら、自動採番 (IDENTITY) に任せた方が良いと思いますよ。

https://sql-oracle.com/sqlserver/?p=1087
http://dev.gem-stones.net/sql-server-identity%E3%81%A7%E8%87%AA%E5%8B%95%E7%9A%84%E3%81%AB%E6%8C%BF%E5%85%A5%E3%81%95%E3%82%8C%E3%81%9Fid%E5%80%A4%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/


> INSERT INTO テーブルA(主キー, フィールド1, フィールド1, フィールド1・・・)
> SELECT MAX(主キー) + 1, フィールド1, フィールド1, フィールド1・・・
> FROM テーブルA
> WHERE 主キー = @主キー

これ、SQL としていろいろおかしいような…。


掲示板投稿時の転記ミスかもしれませんが、第 2 列以降が
すべて「フィールド1」になっている点が明らかに不自然です。

それに何よりも、MAX 関数を使うなら、集合関数以外のフィールドに対して
GROUP BY が指定されていないので、文法面でエラーになるはずですよね。

仮に GROUP BY を転記し忘れただけだとしても、今回のケースで WHERE 句を書いては駄目でしょう。
「MAX(主キー) + 1」によって得たいのは「テーブルA に登録済みの全レコードに対する、最大の主キー値」なのに、
余計な『WHERE 主キー = @主キー』があるために、単一行の中での MAX 集計が行われてしまうので、
これでは「@主キー + 1」と大差がなく、キー競合を防ぐことができません。


> 結局、VB側でフォームからフォームにデータをコピーして更新させるというめんどくさい方法で、

その発言だけだと、どういう処理になっているか読み解けませんが、
アプリを複数同時に立ち上げて、時間差で更新したときに
同じ主キーが発行されないような設計になっているのか、確認しておいた方が良いと思います。
引用返信 編集キー/
■93581 / inTopicNo.8)  Re[5]: レコードをコピーしてキーコードを変える
□投稿者/ WebSurfer (2001回)-(2019/12/23(Mon) 19:59:25)
No93578 (たかし さん) に返信

レスをもらったらそれに対してきちんとフィードバックを返しませんか?

引用返信 編集キー/
■93584 / inTopicNo.9)  Re[6]: レコードをコピーしてキーコードを変える
□投稿者/ たかし (41回)-(2019/12/24(Tue) 08:58:29)
>> INSERT INTO テーブルA(主キー, フィールド1, フィールド1, フィールド1・・・)
>> SELECT MAX(主キー) + 1, フィールド1, フィールド1, フィールド1・・・
>> FROM テーブルA
>> WHERE 主キー = @主キー

>これ、SQL としていろいろおかしいような…。


>掲示板投稿時の転記ミスかもしれませんが、第 2 列以降が
>すべて「フィールド1」になっている点が明らかに不自然です。

>それに何よりも、MAX 関数を使うなら、集合関数以外のフィールドに対して
>GROUP BY が指定されていないので、文法面でエラーになるはずですよね。

>仮に GROUP BY を転記し忘れただけだとしても、今回のケースで WHERE 句を書いては駄目でしょう。
>「MAX(主キー) + 1」によって得たいのは「テーブルA に登録済みの全レコードに対する、最大の主キー値」なのに、
>余計な『WHERE 主キー = @主キー』があるために、単一行の中での MAX 集計が行われてしまうので、
>これでは「@主キー + 1」と大差がなく、キー競合を防ぐことができません。


魔界の仮面弁士様、いつもありがとうございます。

>それに何よりも、MAX 関数を使うなら、集合関数以外のフィールドに対して
>GROUP BY が指定されていないので、文法面でエラーになるはずですよね。

実行時のエラーコードは「この列は集計関数または GROUP BY 句に含まれていません。」です。
WHERE 主キー = @主キー句は削除してみましたが同じエラーとなります。

フィールド1, フィールド1, フィールド1・・・は正しくは
フィールド1, フィールド2, フィールド3・・・でした、すいません。

これらすべてのフィールドに対して「GROUP BY 句に含まれていません。」が発生します。
すみません「集合関数以外のフィールドに対してGROUP BY が指定」されるとはどのようなことなのでしょうか?


引用返信 編集キー/
■93586 / inTopicNo.10)  Re[7]: レコードをコピーしてキーコードを変える
□投稿者/ 魔界の仮面弁士 (2537回)-(2019/12/24(Tue) 11:03:06)
2019/12/24(Tue) 11:04:33 編集(投稿者)

No93584 (たかし さん) に返信
> すみません「集合関数以外のフィールドに対してGROUP BY が指定」されるとはどのようなことなのでしょうか?

「集合関数」というのは、MIN とか MAX とか COUNT とかのことです。
(類似品に「ウィンドウ関数」の MIN とか MAX とか COUNT ってのもあります)


殆どのデータベース製品では、SELECT 句に集合関数が使われている場合、
『集合関数を使っていない列が、すべて GROUP BY 句に指定されている』か、
もしくは『抽出結果のすべての列が、集合関数になっている』必要があります。


SQL の イメージ的にはこんな感じ。


★全社員の中で最大の給与支給額
SELECT MAX(給料支給額) FROM 給与明細 WHERE 年月 = @今月


★男性社員の中で最大の給与支給額
SELECT MAX(給与支給額) FROM 給与明細 WHERE 年月 = @今月 AND 性別='男'


★役職ごとの最大給与額
SELECT 役職コード, MAX(給与支給額) FROM 給与明細 WHERE 年月 = @今月 GROUP BY 役職コード


※これだと、[社員番号] がグループ化されていないのでエラーになる
SELECT 社員番号, MAX(給与支給額) FROM 給与明細
引用返信 編集キー/
■93609 / inTopicNo.11)  Re[8]: レコードをコピーしてキーコードを変える
□投稿者/ もぐお (1回)-(2019/12/26(Thu) 16:41:33)
2019/12/26(Thu) 16:56:56 編集(投稿者)
2019/12/26(Thu) 16:42:35 編集(投稿者)

これでどうでしょう。
主キーで降順のトップを取得した行をメインにinsertしますが、
主キーだけは+した値でinsert


以下のように変更

INSERT INTO テーブルA(主キーX, フィールド1, フィールド2, フィールド3・・・)
SELECT TOP (1) MAX(主キー) + 1 AS 主キーX, フィールド1, フィールド2, フィールド3・・・
FROM テーブルA
ORDER BY 主キー DESC
引用返信 編集キー/
■93610 / inTopicNo.12)  Re[5]: レコードをコピーしてキーコードを変える
□投稿者/ kiku (159回)-(2019/12/26(Thu) 17:12:48)
No93578 (たかし さん) に返信
> ■No93574 (kiku さん) に返信
>>■No93565 (たかし さん) に返信
> >>■No93563 (WebSurfer さん) に返信
>>>>■No93562 (たかし さん) に返信

> 以上のようなストアドプロシージャを書いてみましたが、実行の段階でエラーとなり進むことができません。
> 結局、VB側でフォームからフォームにデータをコピーして更新させるというめんどくさい方法で、
> なんとかやろうとしていたことができました。
> 皆さんありがとうございました。

参考に貼ったURLが良くなったかもしれません。
下記で動作することを確認しました。
最大値+1で追加するサンプルです。

insert into test (syukey, col1, col2)
select
	(select MAX(syukey) + 1 from test),
	col1,
	col2
from test
where syukey = 1

引用返信 編集キー/
■93611 / inTopicNo.13)  Re[6]: レコードをコピーしてキーコードを変える
□投稿者/ 魔界の仮面弁士 (2542回)-(2019/12/26(Thu) 19:15:04)
No93610 (kiku さん) に返信
> 下記で動作することを確認しました。
> 最大値+1で追加するサンプルです。

test テーブルに既存行が 0 件だった場合に、
Max が null を返すでしょうから
初期値となる値(0 とか 1 とか) に
置き換える必要があるのでは。
引用返信 編集キー/
■93613 / inTopicNo.14)  Re[7]: レコードをコピーしてキーコードを変える
□投稿者/ kiku (160回)-(2019/12/27(Fri) 08:31:30)
No93611 (魔界の仮面弁士 さん) に返信
> ■No93610 (kiku さん) に返信
>>下記で動作することを確認しました。
>>最大値+1で追加するサンプルです。
>
> test テーブルに既存行が 0 件だった場合に、
> Max が null を返すでしょうから
> 初期値となる値(0 とか 1 とか) に
> 置き換える必要があるのでは。

ご指摘頂いたことは正しいと思い、
対応したSQL文を作ってみようとみました。

結果としてはその必要がないことがわかりました。

上記SQLは、コピー元を1レコード指定する構造になっており、
存在しないsyukeyを指定した場合(レコード0件の状態)、
0件挿入されることがわかったためです。
エラーにもなりませんでした。

引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ