इस डमी टेबल के साथ काम करना
CREATE TEMP TABLE foo (id int, my_num numeric);
INSERT INTO foo VALUES (1, 12.34)
सबसे पहले, मैंने आपके उदाहरण को सरल और स्वच्छ किया:
-
कुछ शोर हटा दिया जो प्रश्न के लिए अप्रासंगिक है।
-
RETURNS SETOF void
शायद ही समझ में आता है। मैंRETURNS void
का उपयोग करता हूं इसके बजाय। -
मैं
text
का उपयोग करता हूं इसके बजायcharacter varying
, केवल सादगी के लिए। -
डायनेमिक SQL का उपयोग करते समय, आपके पास है SQL इंजेक्शन से बचाव के लिए, मैं
format()
. का उपयोग करता हूँ%I
. के साथ इस मामले में। और भी तरीके हैं।
मूल समस्या यह है कि SQL प्रकार और पहचानकर्ताओं के साथ बहुत कठोर है। आप डायनेमिक टेबल . के साथ काम कर रहे हैं नाम के साथ-साथ रिकॉर्ड के डायनामिक फ़ील्ड नाम . के साथ - एक गुमनाम रिकॉर्ड करें आपके मूल उदाहरण में। Pl/pgSQL इससे निपटने के लिए अच्छी तरह से सुसज्जित नहीं है। Postgres नहीं जानता कि अंदर . क्या है एक अनाम रिकॉर्ड। एक जाने-माने प्रकार . को रिकॉर्ड असाइन करने के बाद ही क्या आप अलग-अलग क्षेत्रों का संदर्भ दे सकते हैं।
यहाँ एक निकट से संबंधित प्रश्न है, जो सेट . करने का प्रयास कर रहा है डायनामिक नाम वाले रिकॉर्ड का एक फ़ील्ड:
डायनेमिक SQL का उपयोग करके कंपोजिट वैरिएबल फ़ील्ड का मान कैसे सेट करें
मूल कार्य
CREATE OR REPLACE FUNCTION getrowdata1(table_name text, id int)
RETURNS void AS
$func$
DECLARE
srowdata record;
reqfield text := 'my_num'; -- assigning at declaration time for convenience
value numeric;
BEGIN
RAISE NOTICE 'id: %', id;
EXECUTE format('SELECT * FROM %I WHERE id = $1', table_name)
USING id
INTO srowdata;
RAISE NOTICE 'srowdata: %', srowdata;
RAISE NOTICE 'srowdatadata.my_num: %', srowdata.my_num;
/* This does not work, even with dynamic SQL
EXECUTE format('SELECT ($1).%I', reqfield)
USING srowdata
INTO value;
RAISE NOTICE 'value: %', value;
*/
END
$func$ LANGUAGE plpgsql;
कॉल करें:
SELECT * from getrowdata1('foo', 1);
टिप्पणी वाला हिस्सा एक अपवाद उठाएगा:
<ब्लॉककोट>रिकॉर्ड डेटा प्रकार में कॉलम "my_num" की पहचान नहीं कर सका:सेलेक्ट * fromgetrowdata(1,'foo')
hstore
आपको अतिरिक्त मॉड्यूल hstore install स्थापित करने की आवश्यकता है इसके लिए। एक बार प्रति डेटाबेस के साथ:
CREATE EXTENSION hstore;
तब सब कुछ इस तरह काम कर सकता था:
CREATE OR REPLACE FUNCTION getrowdata2(table_name text, id int)
RETURNS void AS
$func$
DECLARE
hstoredata hstore;
reqfield text := 'my_num';
value numeric;
BEGIN
RAISE NOTICE 'id: %', id;
EXECUTE format('SELECT hstore(t) FROM %I t WHERE id = $1', table_name)
USING id
INTO hstoredata;
RAISE NOTICE 'hstoredata: %', hstoredata;
RAISE NOTICE 'hstoredata.my_num: %', hstoredata -> 'my_num';
value := hstoredata -> reqfield;
RAISE NOTICE 'value: %', value;
END
$func$ LANGUAGE plpgsql;
कॉल करें:
SELECT * from getrowdata2('foo', 1);
बहुरूपी प्रकार
अतिरिक्त मॉड्यूल स्थापित किए बिना वैकल्पिक।
चूंकि आप अपने रिकॉर्ड चर में एक पूरी पंक्ति का चयन करते हैं, इसलिए एक अच्छी तरह से परिभाषित प्रकार . होता है इसके लिए प्रति परिभाषा। इसका इस्तेमाल करें। कुंजी शब्द है बहुरूपी प्रकार ।
CREATE OR REPLACE FUNCTION getrowdata3(_tbl anyelement, id int)
RETURNS void AS
$func$
DECLARE
reqfield text := 'my_num';
value numeric;
BEGIN
RAISE NOTICE 'id: %', id;
EXECUTE format('SELECT * FROM %s WHERE id = $1', pg_typeof(_tbl))
USING id
INTO _tbl;
RAISE NOTICE '_tbl: %', _tbl;
RAISE NOTICE '_tbl.my_num: %', _tbl.my_num;
EXECUTE 'SELECT ($1).' || reqfield -- requfield must be SQLi-safe or escape
USING _tbl
INTO value;
RAISE NOTICE 'value: %', value;
END
$func$ LANGUAGE plpgsql;
कॉल करें:
SELECT * from getrowdata3(NULL::foo, 1);
-> SQLfiddle
-
मैं (ab-)इनपुट पैरामीटर
_tbl
. का उपयोग करता हूं तीन . के लिए यहाँ उद्देश्य:- अच्छी तरह से परिभाषित प्रकार प्रदान करता है रिकॉर्ड के
- नाम प्रदान करता है तालिका के, स्वचालित रूप से स्कीमा-योग्य
- चर के रूप में कार्य करता है।
-
इस संबंधित उत्तर में अधिक स्पष्टीकरण (अंतिम अध्याय):
विभिन्न चयन प्रश्नों के आउटपुट को वापस करने के लिए एक PL/pgSQL फ़ंक्शन को रिफैक्टर करें