Postgres का उपयोग करके एक समय में 3 तालिकाओं में डेटा डालें


84

मैं एक एकल क्वेरी के साथ 3 तालिकाओं में डेटा सम्मिलित करना चाहता हूं।
मेरी सारणी नीचे दी गई है:

CREATE TABLE sample (
   id        bigserial PRIMARY KEY,
   lastname  varchar(20),
   firstname varchar(20)
);

CREATE TABLE sample1(
   user_id    bigserial PRIMARY KEY,
   sample_id  bigint REFERENCES sample,
   adddetails varchar(20)
);

CREATE TABLE sample2(
   id      bigserial PRIMARY KEY,
   user_id bigint REFERENCES sample1,
   value   varchar(10)
);

मुझे हर प्रविष्टि के बदले में एक कुंजी मिलेगी और मुझे अगली तालिका में उस कुंजी को सम्मिलित करना होगा।
मेरी क्वेरी है:

insert into sample(firstname,lastname) values('fai55','shaggk') RETURNING id;
insert into sample1(sample_id, adddetails) values($id,'ss') RETURNING user_id;
insert into sample2(user_id, value) values($id,'ss') RETURNING id;

लेकिन अगर मैं एकल प्रश्न चलाता हूं तो वे सिर्फ मेरे लिए मान लौटाते हैं और मैं उन्हें अगले प्रश्न में तुरंत पुन: उपयोग नहीं कर सकता।

इसे कैसे प्राप्त किया जाए?

जवाबों:


136

डेटा-संशोधित CTE का उपयोग करें :

WITH ins1 AS (
   INSERT INTO sample(firstname, lastname)
   VALUES ('fai55', 'shaggk')
-- ON     CONFLICT DO NOTHING         -- optional addition in Postgres 9.5+
   RETURNING id AS sample_id
   )
, ins2 AS (
   INSERT INTO sample1 (sample_id, adddetails)
   SELECT sample_id, 'ss' FROM ins1
   RETURNING user_id
   )
INSERT INTO sample2 (user_id, value)
SELECT user_id, 'ss2' FROM ins2;

प्रत्येक INSERTपहले से एक पर निर्भर करता है। यह सुनिश्चित SELECTकरने के बजाय VALUESकि सहायक पंक्ति में कुछ भी नहीं डाला गया है यदि कोई पंक्ति पिछली से वापस नहीं आती है INSERT। (चूंकि पोस्टग्रैज 9.5+ आप इसमें जोड़ सकते हैं ON CONFLICT।)
यह इस तरह से थोड़ा छोटा और तेज है।

आमतौर पर, एक स्थान पर संपूर्ण डेटा पंक्तियाँ प्रदान करना अधिक सुविधाजनक होता है :

WITH data(firstname, lastname, adddetails, value) AS (
   VALUES                              -- provide data here
      ('fai55', 'shaggk', 'ss', 'ss2') -- see below
    , ('fai56', 'XXaggk', 'xx', 'xx2') -- works for multiple input rows
       --  more?                      
   )
, ins1 AS (
   INSERT INTO sample (firstname, lastname)
   SELECT firstname, lastname          -- DISTINCT? see below
   FROM   data
   -- ON     CONFLICT DO NOTHING       -- UNIQUE constraint? see below
   RETURNING firstname, lastname, id AS sample_id
   )
, ins2 AS (
   INSERT INTO sample1 (sample_id, adddetails)
   SELECT ins1.sample_id, d.adddetails
   FROM   data d
   JOIN   ins1 USING (firstname, lastname)
   RETURNING sample_id, user_id
   )
INSERT INTO sample2 (user_id, value)
SELECT ins2.user_id, d.value
FROM   data d
JOIN   ins1 USING (firstname, lastname)
JOIN   ins2 USING (sample_id);

db <> फिडल यहां

आपको स्टैंड-अलोन VALUESअभिव्यक्ति में स्पष्ट प्रकार के कलाकारों की आवश्यकता हो सकती है - जहां लक्ष्य तालिका से डेटा प्रकार प्राप्त होते हैं, से VALUESजुड़ी अभिव्यक्ति के विपरीत INSERT। देख:

यदि कई पंक्तियाँ समान (firstname, lastname)हो सकती हैं , तो आपको पहले के लिए डुप्लिकेट को मोड़ना पड़ सकता है INSERT:

...
INSERT INTO sample (firstname, lastname)
SELECT DISTINCT firstname, lastname FROM data
...

आप CTE के बजाय डेटा स्रोत के रूप में (अस्थायी) तालिका का उपयोग कर सकते हैं data

यह संभवतः (firstname, lastname)तालिका में एक UNIQUE बाधा और ON CONFLICTक्वेरी में एक खंड के साथ संयोजन करने के लिए समझ में आएगा ।

सम्बंधित:


1
पुनरावृत्ति के लिए thanx मैं बाहर लेनदेन रोल में जोड़ सकते हैं, यदि कोई हो असफल प्रविष्टि .yes कैसे कर सकते हैं मैं होता है
फैसल

3
यह एक एकल एसक्यूएल स्टेटमेंट है। व्यक्ति एक ही लेन-देन में कई बयानों को बंडल कर सकता है, लेकिन कोई इसे विभाजित नहीं कर सकता है। इसके अलावा, डेनिस ने अपनी टिप्पणी में क्या कहा। और मैंने अपने उत्तर के कुछ लिंक जोड़े।
एरविन ब्रान्डसेट्टर

2
@mmcrae: हाँ, आप कर सकते हैं। संबंधित: dba.stackexchange.com/questions/151199/…
Erwin Brandstetter

1
@No_name: निश्चित, विभिन्न तरीके। मेरा सुझाव है कि आप विवरण को परिभाषित करने के साथ एक प्रश्न पूछें । आप हमेशा संदर्भ के लिए यहां लिंक कर सकते हैं। या मेरा ध्यान आकर्षित करने के लिए यहां एक टिप्पणी छोड़ दें।
एरविन ब्रांडस्टेट्टर

1
क्या यह एक टाइपो है? आपके जवाब में INSERT INTO sample1 (user_id, adddetails), क्या ऐसा नहीं होना चाहिए (sample_id, addetails)?
एडम ह्यूजेस

19

कुछ इस तरह

with first_insert as (
   insert into sample(firstname,lastname) 
   values('fai55','shaggk') 
   RETURNING id
), 
second_insert as (
  insert into sample1( id ,adddetails) 
  values
  ( (select id from first_insert), 'ss')
  RETURNING user_id
)
insert into sample2 ( id ,adddetails) 
values 
( (select user_id from first_insert), 'ss');

चूंकि इन्सर्ट से इन्सर्ट आई डी की sample2जरूरत नहीं है, मैंने returningअंतिम इंसर्ट से क्लॉज को हटा दिया ।


मुझे चुनिंदा अंदर के मूल्यों के साथ यह दृष्टिकोण पसंद है। यह अधिक सुसंगत है और बयानों के साथ रिटर्न
अलायस को

6

आमतौर पर, आप जटिल प्रश्नों को लिखने से बचने के लिए लेनदेन का उपयोग करेंगे।

http://www.postgresql.org/docs/current/static/sql-begin.html

http://dev.mysql.com/doc/refman/5.7/en/commit.html

आप CTE का उपयोग भी कर सकते हैं, यह मानते हुए कि आपका पोस्टग्रैग टैग सही है। उदाहरण के लिए:

with sample_ids as (
  insert into sample(firstname, lastname)
  values('fai55','shaggk')
  RETURNING id
), sample1_ids as (
  insert into sample1(id, adddetails)
  select id,'ss'
  from sample_ids
  RETURNING id, user_id
)
insert into sample2(id, user_id, value)
select id, user_id, 'val'
from sample1_ids
RETURNING id, user_id;

1
थैंक्स मैं इस क्वेरी में लेन-देन कैसे प्राप्त करूंगा यदि कोई इन्सटॉल फेल हो जाए तो मैं रोलबैक कर सकता हूं
फैसल

1
फिर आप सब कुछ फिर से शुरू करते हैं, बेशक प्रश्नों को सही करने के बाद, क्योंकि पूरा लेनदेन (या सीटीई) वापस लुढ़क जाएगा। Btw, अगर आपके आवेषण कभी-कभी विफल हो रहे हैं, तो आप शायद कुछ गलत कर रहे हैं। एकमात्र मामला जहां किसी इंसर्ट के लिए यह उचित है कि एक अपर्चर परिदृश्य में है जो समवर्ती लेनदेन के दौरान डुप्लिकेट अद्वितीय कुंजियों में चलता है, और तब भी आपको एक एडवाइजरी लॉक या टेबल लॉक मिल सकता है यदि आपको चीजों को बुलेट प्रूफ बनाने की आवश्यकता है।
डेनिस डे बर्नार्डी

3

आप अन्य दो तालिकाओं में सम्मिलित करने के लिए नमूना तालिका पर सम्मिलित ट्रिगर ट्रिगर बना सकते हैं।

एकमात्र मुद्दा जो मैं ऐसा कर रहा हूं, वह यह है कि आपके पास ऐडसेट्स डालने का एक तरीका नहीं है, यह हमेशा खाली रहेगा या इस मामले में एस.एस. नमूना तालिका में कोई कॉलम सम्मिलित करने का कोई तरीका नहीं है, नमूना तालिका में वास्तविक नहीं है, इसलिए आप इसे जन्मजात सम्मिलित करने के साथ नहीं भेज सकते।

एक अन्य विकल्प आपके आवेषण को चलाने के लिए एक संग्रहीत प्रक्रिया बनाना होगा।

आपके पास यह सवाल है कि mysql और postgradql को कौन सी डेटाबेस में रखा गया है?

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.