2010-04-01 16 views
8

में अपडेट से पहले प्रभावित होने वाली पंक्तियों की संख्या की संख्या BEFORE प्रति कथन ट्रिगर में प्रभावित होने वाली पंक्तियों की संख्या जानना चाहती है। क्या यह संभव है?ट्रिगर

समस्या यह है कि मैं केवल उन प्रश्नों को अनुमति देना चाहता हूं जो 4 पंक्तियों तक अपडेट हो जाएंगे। यदि प्रभावित पंक्तियों की गिनती 5 या उससे अधिक है तो मैं त्रुटि उठाना चाहता हूं।

मैं कोड में ऐसा नहीं करना चाहता क्योंकि मुझे डीबी स्तर पर इस जांच की आवश्यकता है। क्या यह सब संभव है?

कि

+0

यदि सामान्य पंक्तियों की तुलना में प्रभावित पंक्तियां अधिक से अधिक हैं, तो मुझे सामान्य क्वेरी + रोलबैक का उपयोग करने पर विचार किया जाता है, और ऐसा लगता है कि यह सबसे अच्छा मूल्य है। ठीक है 99% + में अच्छी पूछताछ होगी (4 अद्यतन पंक्तियां अधिकतम) लेकिन यह सिस्टम के लिए केवल अतिरिक्त सुरक्षा है। इस 'समस्या' वाली तालिका प्रणाली के लिए काफी बड़ी और महत्वपूर्ण है, इसलिए इस तरह की गलत क्वेरी के बाद इसे पुनर्स्थापित करना हर किसी के लिए दर्दनाक हो सकता है। उत्तर के लिए सभी को धन्यवाद। पता नहीं कौन सा स्वीकार करना है क्योंकि उनमें से सभी सहायक जहां :) – sbczk

+0

आप ऐसा क्यों करना चाहते हैं? हो सकता है कि ऐसी अजीब क्वेरी से ऐसा करने का कोई आसान तरीका हो। और क्या है ... तालिका बढ़ने के दौरान गिनती (यदि संभव हो) का उपयोग धीमा हो जाएगा। –

+0

तो आपको लगता है कि जब आपके पास अधिकतम 4 पंक्तियां बदलती हैं तो क्वेरी को गलत टाइप नहीं किया जा सकता है? यह किसी तरह की झूठी सुरक्षा भावना की तरह लगता है। –

उत्तर

1

मैं कुछ इस तरह बना लिया है:

begin; 

create table test (
    id integer 
); 

insert into test(id) select generate_series(1,100); 


create or replace function trg_check_max_4_updated_records() 
returns trigger as $$ 
declare 
    counter_ integer := 0; 
    tablename_ text := 'temptable'; 
begin 
    raise notice 'trigger fired'; 
    select count(42) into counter_ 
     from pg_catalog.pg_tables where tablename = tablename_; 
    if counter_ = 0 then 
     raise notice 'Creating table %', tablename_; 
     execute 'create temporary table ' || tablename_ || ' (counter integer) on commit drop'; 
     execute 'insert into ' || tablename_ || ' (counter) values(1)'; 

     execute 'select counter from ' || tablename_ into counter_; 
     raise notice 'Actual value for counter= [%]', counter_; 
    else 
     execute 'select counter from ' || tablename_ into counter_; 
     execute 'update ' || tablename_ || ' set counter = counter + 1'; 
     raise notice 'updating'; 
     execute 'select counter from ' || tablename_ into counter_; 
     raise notice 'Actual value for counter= [%]', counter_; 

     if counter_ > 4 then 
      raise exception 'Cannot change more than 4 rows in one trancation'; 
     end if; 

    end if; 
    return new; 
end; $$ language plpgsql; 


create trigger trg_bu_test before 
    update on test 
    for each row 
    execute procedure trg_check_max_4_updated_records(); 

update test set id = 10 where id <= 1; 
update test set id = 10 where id <= 2; 
update test set id = 10 where id <= 3; 
update test set id = 10 where id <= 4; 
update test set id = 10 where id <= 5; 

rollback; 

मुख्य विचार पर एक ट्रिगर है कि बनाता है (यदि आवश्यक हो) 'प्रत्येक पंक्ति के लिए अद्यतन करने से पहले' अस्थायी तालिका (है कि कम से हटा दिया गया है लेनदेन का अंत)। इस तालिका में एक मूल्य के साथ केवल एक पंक्ति है, यह वर्तमान लेनदेन में अद्यतन पंक्तियों की संख्या है। प्रत्येक अद्यतन के लिए मूल्य बढ़ता है। यदि मान 4 से बड़ा है, तो लेनदेन बंद कर दिया गया है।

लेकिन मुझे लगता है कि यह आपकी समस्या का गलत समाधान है। ऐसी गलत क्वेरी को चलाने में कोई समस्या है जिसे आपने दो बार लिखा है, इसलिए आपके पास 8 पंक्तियां बदली जाएंगी। पंक्तियों को हटाने या उन्हें छेड़छाड़ करने के बारे में क्या?

0

पर कोई सुराग मैं PostgreSQL के साथ काम किया कभी नहीं किया है के लिए अग्रिम धन्यवाद, तो मेरा उत्तर लागू नहीं हो सकता। एसक्यूएल सर्वर में, अपने ट्रिगर एक संग्रहीत प्रक्रिया है जो करना होगा कॉल कर सकते हैं दो चीजों में से एक:

  1. अभिलेख अद्यतन से प्रभावित होगा की संख्या निर्धारित करने के लिए एक COUNT का चयन करें (*) को पूरा करें, और उसके बाद ही अमल अद्यतन करता है, तो गिनती 4 या कम
  2. एक सौदे के भीतर अद्यतन प्रदर्शन करना है, और केवल लेन-देन के लिए प्रतिबद्ध है, तो प्रभावित पंक्तियों की लौटे संख्या 4 या कम

नंबर 1 कमजोर समय है (संख्या है अद्यतन द्वारा प्रभावित रिकॉर्ड COUNT (*) चेक और वास्तविक अद्यतन के बीच बदल सकते हैं। संख्या 2 बहुत अक्षम है, अगर कई सीए हैं एसईएस जहां अद्यतन पंक्तियों की संख्या 4 से अधिक है

1

पोस्टग्रेएसक्यूएल में दो types of triggers है: पंक्ति और कथन ट्रिगर्स। पंक्ति ट्रिगर केवल पंक्ति के संदर्भ में ही काम करती है ताकि आप उनका उपयोग न कर सकें। दुर्भाग्य से, "पहले" कथन don't see ट्रिगर करता है कि किस प्रकार का परिवर्तन होने वाला है, इसलिए मुझे विश्वास नहीं है कि आप उन का उपयोग भी कर सकते हैं।

उस पर आधारित, मैं कहूंगा कि यह संभावना नहीं है कि आप ट्रिगर्स का उपयोग करके डेटाबेस में उस तरह की सुरक्षा का निर्माण करने में सक्षम होंगे, जब तक कि आप "बाद" ट्रिगर का उपयोग नहीं करते हैं और लेनदेन को वापस लेते हैं हालत संतुष्ट नहीं है। गलत साबित होने पर बुरा नहीं लगेगा। :)

1

सीरियलज़ेबल अलगाव स्तर का उपयोग करने पर एक नज़र डालें। मेरा मानना ​​है कि यह आपको आपके लेनदेन के भीतर डेटाबेस डेटा का एक सतत दृश्य देगा। फिर आप विकल्प # 1 का उपयोग कर सकते हैं कि MusiGenesis का उल्लेख समय की भेद्यता के बिना किया गया है। प्रमाणित करने के लिए निश्चित रूप से इसका परीक्षण करें।

+0

हां भूल गया है या छोड़ने का सबसे अच्छा तरीका है सभी लेनदेन के रूप में डेटाबेस दक्षता एक करके एक किया जाएगा :( –

2

एक ऐसा फ़ंक्शन लिखें जो आपके लिए पंक्तियों को अपडेट करता है या रोलबैक करता है। खराब शैली स्वरूपण के लिए खेद है।

create function update_max(varchar, int) 
RETURNS void AS 
$BODY$ 

DECLARE 

    sql ALIAS FOR $1; 
    max ALIAS FOR $2; 
    rcount INT; 

BEGIN 

    EXECUTE sql; 
    GET DIAGNOSTICS rcount = ROW_COUNT; 

    IF rcount > max THEN 

     --ROLLBACK; 
     RAISE EXCEPTION 'Too much rows affected (%).', rcount; 

    END IF; 

    --COMMIT; 

END; 

$BODY$ LANGUAGE plpgsql 

तब की तरह

select update_max('update t1 set id=id+10 where id < 4', 3); 

इसे कहते हैं जहाँ आपके एसक्यूएल-वक्तव्य IST पहले परम और 2 अपनी अधिकतम पंक्तियाँ।

2

Simon का अच्छा विचार था लेकिन उनका कार्यान्वयन अनावश्यक रूप से जटिल है। यह मेरा प्रस्ताव है:

create or replace function trg_check_max_4()     
returns trigger as $$ 
begin 
     perform true from pg_class 
       where relname='check_max_4' and relnamespace=pg_my_temp_schema(); 
     if not FOUND then 
       create temporary table check_max_4 
         (value int check (value<=4)) 
         on commit drop; 
       insert into check_max_4 values (0); 
     end if; 

     update check_max_4 set value=value+1; 
     return new; 
end; $$ language plpgsql; 
संबंधित मुद्दे