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$;