تحديث استنادا إلى Sacquery Fails
سؤال
أحاول القيام التحديث التالي في Oracle 10GR2:
update
(select voyage_port_id, voyage_id, arrival_date, port_seq,
row_number() over (partition by voyage_id order by arrival_date) as new_seq
from voyage_port) t
set t.port_seq = t.new_seq
Voyage_port_id هو المفتاح الأساسي، Voyage_id هو مفتاح أجنبي. أحاول تعيين رقم التسلسل بناء على التواريخ داخل كل رحلة.
ومع ذلك، فشل أعلاه مع ORA-01732: عملية معالجة البيانات غير قانونية حول هذا الرأي
ما هي المشكلة وكيف يمكنني تجنب ذلك؟
المحلول
نظرا لأنك لا يمكنك تحديث السلقي row_number
, ، سيكون عليك حساب رقم الصف في set
جزء من التحديث. في البداية حاولت هذا:
update voyage_port a
set a.port_seq = (
select
row_number() over (partition by voyage_id order by arrival_date)
from voyage_port b
where b.voyage_port_id = a.voyage_port_id
)
ولكن هذا لا يعمل، لأن الاسمية الفرعية تحدد فقط صف واحد، ثم row_number()
هو دائما 1. استخدام تدعك استقبال آخر يسمح بنتيجة ذات معنى:
update voyage_port a
set a.port_seq = (
select c.rn
from (
select
voyage_port_id
, row_number() over (partition by voyage_id
order by arrival_date) as rn
from voyage_port b
) c
where c.voyage_port_id = a.voyage_port_id
)
يعمل، ولكن أكثر تعقيدا مما كنت أتوقع لهذه المهمة.
نصائح أخرى
يمكنك تحديث بعض المشاهدات، ولكن هناك قيود وواحدة هي أن الرأي يجب ألا يحتوي على وظائف تحليلية. يرى مرجع لغة SQL على التحديث والبحث عن الحدوث الأول من "التحليل".
سيعمل ذلك، شريطة عدم وجود رحلة يزور أكثر من منفذ واحد في نفس اليوم (أو تتضمن التواريخ مكونا زمنيا يجعلها فريدة من نوعها):
update voyage_port vp
set vp.port_seq =
( select count(*)
from voyage_port vp2
where vp2.voyage_id = vp.voyage_id
and vp2.arrival_date <= vp.arrival_date
)
أعتقد أن هذا يتعامل مع القضية التي تزور فيها الرحلة أكثر من منفذ واحد يوميا ولا يوجد مكون أطول (على الرغم من أن تسلسل المنافذ التي تمت زيارتها في نفس اليوم، فإنها تعسفية بعد ذلك):
update voyage_port vp
set vp.port_seq =
( select count(*)
from voyage_port vp2
where vp2.voyage_id = vp.voyage_id
and (vp2.arrival_date <= vp.arrival_date)
or ( vp2.arrival_date = vp.arrival_date
and vp2.voyage_port_id <= vp.voyage_port_id
)
)
لا تعتقد أنه يمكنك تحديث جدول مشتق، وأعد كتابته
update voyage_port
set port_seq = t.new_seq
from
voyage_port p
inner join
(select voyage_port_id, voyage_id, arrival_date, port_seq,
row_number() over (partition by voyage_id order by arrival_date) as new_seq
from voyage_port) t
on p.voyage_port_id = t.voyage_port_id
يجب أن يكون الرمز المميز الأول بعد التحديث اسم الجدول للتحديث، ثم أعمدة التحديث. لست متأكدا مما تحاول تحقيقه مع عبارة SELECT حيث أنه، ولكن يمكنك " تحديث النتيجة المجموعة من تحديد قانونيا.
نسخة من SQL، تخمين ما لديك في الاعتبار، قد تبدو وكأنها ...
update voyage_port t
set t.port_seq = (<select statement that generates new value of port_seq>)
ملاحظة: لاستخدام عبارة SELECT لتعيين قيمة مثل هذا، يجب عليك التأكد من أنه سيتم إرجاع صف واحد فقط من التحديد!
تحرير: بيان تعديل أعلاه لتعكس ما كنت أحاول شرحه. تم الرد على السؤال بشكل جيد للغاية بواسطة andomar أعلاه