PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

डायनेमिक SQL का उपयोग करके समग्र चर फ़ील्ड का मान कैसे सेट करें

hstore के साथ तेज़

चूंकि पोस्टग्रेज 9.0 , अतिरिक्त मॉड्यूल के साथ hstore आपके डेटाबेस में स्थापित #= . के साथ एक बहुत ही सरल और तेज़ समाधान है ऑपरेटर कि ...

<ब्लॉकक्वॉट>

[s] फ़ील्ड को record में बदलें hstore . से मेल खाने वाले मानों के साथ ।

मॉड्यूल स्थापित करने के लिए:

CREATE EXTENSION hstore;

उदाहरण:

SELECT my_record #= '"field"=>"value"'::hstore;  -- with string literal
SELECT my_record #= hstore(field, value);        -- with values

मानों को text में डालना होगा और पीछे, जाहिर है।

उदाहरण plpgsql अधिक विवरण के साथ कार्य करता है:

  • ट्रिगर फ़ंक्शन में अंतहीन लूप
  • पोस्टग्रेज ट्रिगर में कुंजी द्वारा NEW को असाइन करें

अब json के साथ काम करता है / jsonb , भी!

json . के समान समाधान हैं (पृष्ठ 9.3+) या jsonb (पृष्ठ 9.4+)

SELECT json_populate_record (my_record, json_build_object('key', 'new-value');

कार्यक्षमता अनिर्दिष्ट थी, लेकिन यह पोस्टग्रेज 13 के बाद से आधिकारिक है। मैनुअल:

<ब्लॉकक्वॉट>

हालांकि, यदि आधार NULL नहीं है तो इसमें शामिल मानों का उपयोग बेजोड़ स्तंभों के लिए किया जाएगा।

तो आप कोई भी मौजूदा पंक्ति ले सकते हैं और मनमानी फ़ील्ड भर सकते हैं (इसमें जो लिखा है उसे ओवरराइट करना)।

json . के प्रमुख लाभ बनाम hstore :

  • स्टॉक पोस्टग्रेज के साथ काम करता है इसलिए आपको अतिरिक्त मॉड्यूल की आवश्यकता नहीं है।
  • नेस्टेड सरणी और समग्र प्रकारों के लिए भी काम करता है।

मामूली नुकसान:थोड़ा धीमा।

विवरण के लिए @ गीर का जोड़ा उत्तर देखें।

बिना hstore . के और json

यदि आप पुराने संस्करण पर हैं या अतिरिक्त मॉड्यूल स्थापित नहीं कर सकते हैं hstore या यह नहीं मान सकता कि यह स्थापित है, मैंने पहले जो पोस्ट किया था उसका एक बेहतर संस्करण यहां दिया गया है। अभी भी hstore . से धीमी है ऑपरेटर, हालांकि:

CREATE OR REPLACE FUNCTION f_setfield(INOUT _comp_val anyelement
                                          , _field text, _val text)
  RETURNS anyelement
  LANGUAGE plpgsql STABLE AS
$func$
BEGIN

EXECUTE 'SELECT ' || array_to_string(ARRAY(
      SELECT CASE WHEN attname = _field
                THEN '$2'
                ELSE '($1).' || quote_ident(attname)
             END AS fld
      FROM   pg_catalog.pg_attribute
      WHERE  attrelid = pg_typeof(_comp_val)::text::regclass
      AND    attnum > 0
      AND    attisdropped = FALSE
      ORDER  BY attnum
      ), ',')
USING  _comp_val, _val
INTO   _comp_val;

END
$func$;

कॉल करें:

CREATE TEMP TABLE t( a int, b text);  -- Composite type for testing
SELECT f_setfield(NULL::t, 'a', '1');

नोट

  • मान का एक स्पष्ट कलाकार _val लक्ष्य डेटा प्रकार के लिए आवश्यक नहीं है, गतिशील क्वेरी में एक स्ट्रिंग अक्षर स्वचालित रूप से मजबूर हो जाएगा, pg_type पर सबक्वायरी को छोड़कर . लेकिन मैंने इसे एक कदम आगे बढ़ाया:

  • बदलें quote_literal(_val) USING . के माध्यम से प्रत्यक्ष मूल्य प्रविष्टि के साथ खंड। एक फ़ंक्शन कॉल और दो कास्ट बचाता है, और वैसे भी सुरक्षित है। text आधुनिक पोस्टग्रेएसक्यूएल में स्वचालित रूप से लक्ष्य प्रकार के लिए मजबूर किया जाता है। (9.1 से पहले के संस्करणों के साथ परीक्षण नहीं किया।)

  • array_to_string(ARRAY()) string_agg() . से तेज़ है ।

  • कोई चर आवश्यक नहीं, कोई DECLARE . कम असाइनमेंट।

  • डायनेमिक SQL में कोई सबक्वेरी नहीं। ($1).field तेज़ है।

  • pg_typeof(_comp_val)::text::regclass
    ऐसा ही करता है
    (SELECT typrelid FROM pg_catalog.pg_type WHERE oid = pg_typeof($1)::oid)
    वैध मिश्रित प्रकारों के लिए, बस तेज़।
    यह अंतिम संशोधन इस धारणा पर बनाया गया है कि pg_type.typname हमेशा संबद्ध pg_class.relname . के समान होता है पंजीकृत समग्र प्रकारों के लिए, और डबल कास्ट सबक्वेरी को प्रतिस्थापित कर सकता है। मैंने इस परीक्षण को सत्यापित करने के लिए एक बड़े डेटाबेस में चलाया, और यह अपेक्षा के अनुरूप खाली आया:

    SELECT *
    FROM   pg_catalog.pg_type t
    JOIN   pg_namespace  n ON n.oid = t.typnamespace
    WHERE  t.typrelid > 0  -- exclude non-composite types
    AND    t.typrelid IS DISTINCT FROM
          (quote_ident(n.nspname ) || '.' || quote_ident(typname))::regclass
  • एक INOUT का उपयोग पैरामीटर एक स्पष्ट RETURN . की आवश्यकता को कम करता है . यह सिर्फ एक नोटेशनल शॉर्टकट है। पावेल इसे पसंद नहीं करेंगे, वह एक स्पष्ट RETURN पसंद करते हैं बयान ...

सब कुछ एक साथ मिलाकर यह दुगुना तेज़ . है पिछले संस्करण के रूप में।

मूल (पुराना) उत्तर:

परिणाम एक ऐसा संस्करण है जो ~ 2.25 गुना तेज . है . लेकिन मैं शायद इसे पावेल के दूसरे संस्करण के निर्माण के बिना नहीं कर सकता था।

इसके अतिरिक्त, यह संस्करण अधिकांश कास्टिंग से बचा जाता है एक ही क्वेरी के भीतर सब कुछ करके पाठ और वापस करने के लिए, इसलिए यह बहुत कम त्रुटि प्रवण होना चाहिए।
PostgreSQL 9.0 और 9.1 के साथ परीक्षण किया गया ।

CREATE FUNCTION f_setfield(_comp_val anyelement, _field text, _val text)
  RETURNS anyelement
  LANGUAGE plpgsql STABLE AS
$func$
DECLARE
   _list text;
BEGIN
_list := (
   SELECT string_agg(x.fld, ',')
   FROM  (
      SELECT CASE WHEN a.attname = $2
              THEN quote_literal($3) || '::'|| (SELECT quote_ident(typname)
                                                FROM   pg_catalog.pg_type
                                                WHERE  oid = a.atttypid)
              ELSE quote_ident(a.attname)
             END AS fld
      FROM   pg_catalog.pg_attribute a 
      WHERE  a.attrelid = (SELECT typrelid
                           FROM   pg_catalog.pg_type
                           WHERE  oid = pg_typeof($1)::oid)
      AND    a.attnum > 0
      AND    a.attisdropped = false
      ORDER  BY a.attnum
      ) x
   );

EXECUTE 'SELECT ' || _list || ' FROM  (SELECT $1.*) x'
USING  $1
INTO   $1;

RETURN $1;
END
$func$;


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. pg_stat_activity का उपयोग कैसे करें?

  2. SQLAlchemy, Psycopg2 और Postgresql COPY

  3. किसी फ़ंक्शन से कोई क्वेरी लौटाएं?

  4. जेपीए और हाइबरनेट के साथ केवल-पढ़ने और पढ़ने-लिखने के लेनदेन को कैसे विभाजित करें

  5. Postgresql GROUP_CONCAT समकक्ष?