كيف يمكنك إنشاء رقم مراجعة تزايد تلقائي فريد لمفتاح في PGSQL؟

StackOverflow https://stackoverflow.com/questions/912057

سؤال

على افتراض أن لدي الجداول التالية.

PARENT: PARENT_ID serial, DESCRIPTION character varying(50)

CHILD: PARENT_ID integer, CHILD_ID integer, DESCRIPTION character varying(50)

ما أود رؤيته هو كل صف في الطفل وجود طفل يبدأ في 1 وزيادات بنسبة 1، فريدة من نوعها PER_ID. سيكون مشابها لرقم المراجعة. علي سبيل المثال..

PARENT_ID 1, CHILD_ID 1
PARENT_ID 1, CHILD_ID 2
PARENT_ID 1, CHILD_ID 3
PARENT_ID 2, CHILD_ID 1
PARENT_ID 3, CHILD_ID 1
PARENT_ID 3, CHILD_ID 2

هل هناك أي طريقة للحصول على قيمة الطفل المعينة تلقائيا، مثل تسلسل أو قيود، فقط مع القدرة على إعادة استخدام طفل_ID تم حذفها؟ الطريقة الوحيدة التي يمكنني معرفةها هي تأثير هذا SQL.

INSERT INTO child SELECT parent_id, MAX(child_id)+1, 'description' FROM child WHERE parent_id = :PARENT_ID GROUP BY parent_id

هذا قليلا من الاختراق رغم ذلك. أدرك أن تطبيع قاعدة البيانات يشير إلى أنه لا ينبغي أن يكون لديك مفتاح واحد يتعلق بآخر، لكن ليس لدي هذا الخيار لأسباب أخرى. أيه أفكار؟

تعديل: العنوان القبيح. إذا كان أي منكم، فيمكن لأي من الأشخاص المرتفعين التفكير في واحد أكثر دقة، فلا تتردد في تغييره.

هل كانت مفيدة؟

المحلول

أود أن أقترح باستخدام:

CHILD: PARENT_ID integer, CHILD_ID serial, DESCRIPTION character varying(50)

عندما تحتاج إلى الحصول على النتيجة المرجوة:

  • يمكنك حساب الصفوف على جانب العميل.

  • عند اختيار الصفوف حيث Parent_id =؟ يمكنك استخدام التسلسل المؤقت.

  • في قريبا تصدر postgresql 8.4 يمكنك استخدام وظائف Windowing مثل هذا:

    $ create table child (parent_id integer, child_id serial);
    NOTICE:  CREATE TABLE will create implicit sequence "child_child_id_seq" for serial column "child.child_id"
    CREATE TABLE
    
    $ insert into child (parent_id) values (1), (1), (1), (2), (3), (3);
    
    $ select * from child;
     parent_id | child_id 
    -----------+----------
             1 |        1
             1 |        2
             1 |        3
             2 |        4
             3 |        5
             3 |        6
    (6 rows)
    
    $ select parent_id, row_number() over (partition by parent_id order by child_id) from child;
     parent_id | row_number 
    -----------+------
             1 |          1
             1 |          2
             1 |          3
             2 |          1
             3 |          1
             3 |          2
    (6 rows)
    

إنه سريع للغاية وسهل التنفيذ وسيتم توفيره بشكل جيد للغاية حيث لن تكون هناك قضايا متزامفة تقلق بشأنها.

نصائح أخرى

أن إدراج ليست القصة بأكملها. ستحتاج أيضا إلى التعامل مع حذف لإغلاق الفجوة التي تم إنشاؤها إذا كنت تريد حقا أن تكون الأرقام متجاورة.

سيكون اقتراحي هو استخلاص هذه القيمة كما تحتاج إليها. ما الذي يحدد ترتيب الرقم؟ إذا كان التاريخ الذي تم إدخاله في النظام، فقم بإضافة هذا التاريخ إلى طاولتك ووضع PK عبر Parent_ID وهذا التاريخ، ثم يمكنك الخروج بسهولة مع الرقم إما من خلال SQL أو في الواجهة الأمامية أثناء حاجة إليها.

يمكنك استخدام رقم إصدار زيادة في الجدول الأصل وتعيين معرف الطفل إلى هذه القيمة وزيادة ذلك. ربما تحتاج إلى تحديث الصف الأصل وأدخل صف الطفل في معاملة واحدة.

BEGIN
-- Get and hold onto parent_id and version values.
SELECT PARENT_ID, VERSION FROM PARENT WHERE PARENT_ID = :PARENT_ID;
-- Use the values to insert into the child table
INSERT INTO CHILD (PARENT_ID, CHILD_ID) VALUES (:PARENT_ID, :VERSION);
-- Update the version using an optimistic lock.
UPDATE PARENT SET VERSION = VERSION + 1 WHERE PARENT_ID = :PARENT_ID AND 
                                              VERSION = :VERSION_ID
-- If no rows are updated rollback the transaction and try again.
END

سيضمن ذلك أن معرفات الأطفال تصاعدا بدقة، ولكن لن إعادة استخدام قيم المعرف بعد الحذف. إذا كان بإمكانك تجنب قرض إعادة استخدام المعرفات القديمة، فسيؤدي بتبسيط الحل الخاص بك (والحل سيكون أكثر كفاءة). اذا أنت يجب أن إعادة استخدام معرفات إعادة استخدامها ثم لديك خيارين، أولا الحل الذي حددته أعلاه، ولكن عند حذف إعادة ترقيم جميع القيم التي تحدث بعد المحذوفة. الخيار الآخر هو أن يكون هناك نوع من الوظائف التي تقوم بمسح معرفات الطفل بالترتيب ويقارنها بمجموعة من الأرقام المتسلسلة وإرجاع القيمة عند عدم العثور على أول واحد. كل من هذه الحلول أكثر تعقيدا وسيكون بطيئا حيث ستحتاج إلى إخراج قفل صفيا لمنع التحديثات المتزامنة وإما الإدراج أو كلا الإدراج والحذف ستحمل عقوبة O (ن).

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