बहुत कुछ है मैं अलग ढंग से और बहुत प्रभाव से करूंगा।
तालिका परिभाषा
तालिका परिभाषा और नामकरण सम्मेलनों के साथ शुरू करना। ये ज्यादातर सिर्फ राय हैं:
CREATE TEMP TABLE conta (conta_id bigint primary key, ...);
CREATE TEMP TABLE departamento (
dept_id serial PRIMARY KEY
, master_id int REFERENCES departamento (dept_id)
, conta_id bigint NOT NULL REFERENCES conta (conta_id)
, nome text NOT NULL
);
प्रमुख बिंदु
-
क्या आप वाकई एक
bigserial
विभागों के लिए? इस ग्रह पर बहुत कम हैं। एक सादाserial
पर्याप्त होना चाहिए। -
मैं शायद ही कभी
चरित्र भिन्न
का उपयोग करता हूं लंबाई प्रतिबंध के साथ। कुछ अन्य RDBMS के विपरीत, प्रतिबंध का उपयोग करने से कोई प्रदर्शन लाभ नहीं होता है। एकचेक करें
जोड़ें बाधा यदि आपको वास्तव में अधिकतम लंबाई लागू करने की आवश्यकता है। मैं सिर्फtext
का उपयोग करता हूं , अधिकतर और खुद को परेशानी से बचाएं।ए> -
मैं एक नामकरण सम्मेलन का सुझाव देता हूं जहां विदेशी कुंजी कॉलम संदर्भित कॉलम के साथ नाम साझा करता है, इसलिए
master_id
master_fk
. के बजाय , आदि।उपयोग
. का उपयोग करने की भी अनुमति देता है जुड़ने में। -
और मैं शायद ही कभी गैर-वर्णनात्मक कॉलम नाम का उपयोग करें
id
.dept_id
का उपयोग करना इसके बजाय यहाँ।
PL/pgSQL फ़ंक्शन
इसे बड़े पैमाने पर सरल बनाया जा सकता है:
CREATE OR REPLACE FUNCTION f_retornar_plpgsql(lista_ini_depts VARIADIC int[])
RETURNS int[] AS
$func$
DECLARE
_row departamento; -- %ROWTYPE is just noise
BEGIN
IF NOT EXISTS ( -- simpler in 9.1+, see below
SELECT FROM pg_catalog.pg_class
WHERE relnamespace = pg_my_temp_schema()
AND relname = 'tbl_temp_dptos') THEN
CREATE TEMP TABLE tbl_temp_dptos (dept_id bigint NOT NULL)
ON COMMIT DELETE ROWS;
END IF;
FOR i IN array_lower(lista_ini_depts, 1) -- simpler in 9.1+, see below
.. array_upper(lista_ini_depts, 1) LOOP
SELECT * INTO _row -- since rowtype is defined, * is best
FROM departamento
WHERE dept_id = lista_ini_depts[i];
CONTINUE WHEN NOT FOUND;
INSERT INTO tbl_temp_dptos VALUES (_row.dept_id);
LOOP
SELECT * INTO _row
FROM departamento
WHERE dept_id = _row.master_id;
EXIT WHEN NOT FOUND;
INSERT INTO tbl_temp_dptos
SELECT _row.dept_id
WHERE NOT EXISTS (
SELECT FROM tbl_temp_dptos
WHERE dept_id =_row.dept_id);
END LOOP;
END LOOP;
RETURN ARRAY(SELECT dept_id FROM tbl_temp_dptos);
END
$func$ LANGUAGE plpgsql;
कॉल करें:
SELECT f_retornar_plpgsql(2, 5);
या:
SELECT f_retornar_plpgsql(VARIADIC '{2,5}');
-
$1 के लिए उपनाम
पुराना सिंटैक्स है और निराश . इसके बजाय फ़ंक्शन पैरामीटर का उपयोग करें। -
VARIADIC
पैरामीटर कॉल करने के लिए इसे और अधिक सुविधाजनक बनाता है। संबंधित: -
आपको
निष्पादित
की आवश्यकता नहीं है गतिशील तत्वों के बिना प्रश्नों के लिए। यहां हासिल करने के लिए कुछ नहीं है। -
तालिका बनाने के लिए आपको अपवाद हैंडलिंग की आवश्यकता नहीं है। मैनुअल को उद्धृत करना यहां :
-
पोस्टग्रेज 9.1 या बाद के संस्करण में
CREATE है अस्थायी तालिका यदि मौजूद नहीं है
. मैं सशर्त रूप से अस्थायी तालिका बनाने के लिए 9.0 के लिए वैकल्पिक हल का उपयोग करता हूं। -
पोस्टग्रेज 9.1
FOREACH
भी ऑफर करते हैं एक सरणी के माध्यम से लूप करने के लिए ।
जो कुछ भी कहा गया है, वह यह है:आपको इसकी अधिकतर आवश्यकता नहीं है।
rCTE के साथ SQL फ़ंक्शन
पोस्टग्रेज 9.0 में भी, एक रिकर्सिव CTE इसे बहुत आसान बनाता है :
CREATE OR REPLACE FUNCTION f_retornar_sql(lista_ini_depts VARIADIC int[])
RETURNS int[] AS
$func$
WITH RECURSIVE cte AS (
SELECT dept_id, master_id
FROM unnest($1) AS t(dept_id)
JOIN departamento USING (dept_id)
UNION ALL
SELECT d.dept_id, d.master_id
FROM cte
JOIN departamento d ON d.dept_id = cte.master_id
)
SELECT ARRAY(SELECT DISTINCT dept_id FROM cte) -- distinct values
$func$ LANGUAGE sql;
वही कॉल।
स्पष्टीकरण के साथ निकट से संबंधित उत्तर:
SQL Fiddle दोनों को प्रदर्शित करता है।