users
(列email
、name
、id
)とuser_details
(列username
を含む)の2つのテーブルがあります。 、address
、details
)。現在、user_details
のユーザー名には、IDとメールの組み合わせが入力されています。テーブルにすべてのIDが必要です。現在電子メールが入力されているユーザーの詳細の行を、ユーザーテーブルの同じ電子メールの行と照合し、その行のIDで更新する方法はありますか?以下のクエリを試しました:
update
(select distinct
u.sid as new_id,
ud.username as id
from user_details ud
inner join users u on
lower(ud.username) = u.email) up set up.id = up.new_id;
2つのテーブルを結合してから結合を更新しようとすると、次のエラーが発生します。
SQLエラー:ORA-01779:非キー保存テーブル01779にマップする列は変更できません。00000-"非キー保存テーブルにマップする列は変更できません"
説明している状況に似た状況を作成しようとするとき、Oracle 12cを使用して、次のDDLコード(制約がないことに注意)を使用しました。
テスト設定
create table users (
email varchar2(32)
, name varchar2(32)
, sid varchar2(32) -- <- assumption: data type NOT number
);
create table user_details (
username varchar2(32) -- <- populated with a mix of ids and emails
, address varchar2(64)
, details varchar2(64)
);
テストデータを挿入すると、テーブルには...
SQL> select * from users;
EMAIL NAME SID
[email protected] name_1 1
[email protected] name_2 2
[email protected] name_3 3
-- user_details: username contains "a mix of ID's and Email's"
SQL> select * from user_details;
USERNAME ADDRESS DETAILS
1 address_1 details_1
[email protected] more details (user 1)
2 address_2 details_2
[email protected] more details (user 2)
3 address_3 details_3
[email protected] more details (user 3)
3 --- some more details (user 3)
問題
オリジナルのUPDATEを使用すると、「ORA-01732」が取得されます
update
(select distinct
u.sid as new_id,
ud.username as id
from user_details ud
inner join users u on
lower(ud.username) = u.email) up set up.id = up.new_id ;
Error at Command Line : 2 Column : 1
Error report -
SQL Error: ORA-01732: data manipulation operation not legal on this view
01732. 00000 - "data manipulation operation not legal on this view"
DISTINCTなしで同じUPDATEを実行すると、「ORA-01779」が得られます
update (
select
u.sid as new_id,
ud.username as id
from user_details ud
inner join users u on lower(ud.username) = u.email
) up
set up.id = up.new_id ;
SQL Error: ORA-01779: cannot modify a column which maps to a non key-preserved table
01779. 00000 - "cannot modify a column which maps to a non key-preserved table"
*Cause: An attempt was made to insert or update columns of a join view which
map to a non-key-preserved table.
*Action: Modify the underlying base tables directly.
SETのサブクエリでこれを実行できるかどうかを見てみましょう...(まだ喜びはありません)
UPDATE user_details
SET user_details.username =
(
SELECT DISTINCT users.sid AS new_id
FROM users, user_details
WHERE LOWER(user_details.username) = users.email
);
Error report -
ORA-01427: single-row subquery returns more than one row
ソリューション
たぶん、次の解決策を検討したいかもしれません:元のuser_detailsテーブルをそのままにしておきます。 user_detailsから必要なものをすべて選択して、新しいテーブルを作成します。
create table userdetails_new
as
select
u.sid as new_id -- <- sid corresponds to an email address in users
, ud.address as address
, ud.details as details
from user_details ud
join users u on lower(ud.username) = u.email
union
select
username -- <- username that is NOT an email address
, address
, details
from user_details
where username not like '%@%' ;
新しい「ユーザーの詳細」テーブルには、...
SQL> select * from userdetails_new;
NEW_ID ADDRESS DETAILS
1 more details (user 1)
1 address_1 details_1
2 more details (user 2)
2 address_2 details_2
3 more details (user 3)
3 some more details (user 3)
3 address_3 details_3
ここで、次のような制約を追加することもできます。
alter table users add unique(sid);
alter table userdetails_new
add constraint fkey_userdetails
foreign key (new_id) references users (sid) ;
これには他の解決策があると確信しています。ただし、推奨される手順により、必要な限り、つまり更新/変換が正常に行われたことを確認するまで、元の「user_details」データを保持できます。 Dbfiddle here。
テーブルを更新するように指示する必要がありますが、現在はクエリを更新するように指示しています
UPDATE user_details
SET user_details.id =
(
SELECT DISTINCT users.sid AS new_id
FROM users
WHERE LOWER(user_details.username) = users.email)
);