سؤال

أحاول القيام التحديث التالي في 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 أعلاه

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top