बेहतर क्वेरी
शुरुआत के लिए आप वाक्य रचना को ठीक कर सकते हैं, सरल बना सकते हैं और थोड़ा स्पष्ट कर सकते हैं:
SELECT *
FROM (
SELECT p.person_id, p.name, p.team, sum(s.score)::int AS score
,rank() OVER (PARTITION BY p.team
ORDER BY sum(s.score) DESC)::int AS rnk
FROM person p
JOIN score s USING (person_id)
GROUP BY 1
) sub
WHERE rnk < 3;
-
मेरे अद्यतन तालिका लेआउट पर निर्माण। नीचे बेला देखें।
-
आपको अतिरिक्त सबक्वायरी की आवश्यकता नहीं है। विंडो फ़ंक्शन बाद निष्पादित किए जाते हैं समग्र कार्य, ताकि आप इसे प्रदर्शित की तरह घोंसला बना सकें।
-
"रैंक" के बारे में बात करते समय, आप शायद
रैंक ()
. का उपयोग करना चाहते हैं , नहींrow_number()
। -
मान लें कि
people.people_id
PK है, आपGROUP BY
को सरल बना सकते हैं । -
सभी कॉलम नामों को तालिका-योग्य बनाना सुनिश्चित करें जो अस्पष्ट हो सकते हैं
PL/pgSQL फ़ंक्शन
तब मैं एक plpgsql फ़ंक्शन लिखूंगा जो आपके चर भागों के लिए पैरामीटर लेता है। a
को लागू करना - सी
आपके अंक का। डी
अस्पष्ट है, इसे आपके ऊपर जोड़ने के लिए छोड़ दिया गया है।
CREATE OR REPLACE FUNCTION f_demo(_agg text DEFAULT 'sum'
, _left_join bool DEFAULT FALSE
, _where_name text DEFAULT NULL)
RETURNS TABLE(person_id int, name text, team text, score int, rnk int) AS
$func$
DECLARE
_agg_op CONSTANT text[] := '{count, sum, avg}'; -- allowed functions
_sql text;
BEGIN
-- assert --
IF _agg ILIKE ANY (_agg_op) THEN
-- all good
ELSE
RAISE EXCEPTION '_agg must be one of %', _agg_op;
END IF;
-- query --
_sql := format('
SELECT *
FROM (
SELECT p.person_id, p.name, p.team, %1$s(s.score)::int AS score
,rank() OVER (PARTITION BY p.team
ORDER BY %1$s(s.score) DESC)::int AS rnk
FROM person p
%2$s score s USING (person_id)
%3$s
GROUP BY 1
) sub
WHERE rnk < 3
ORDER BY team, rnk'
, _agg
, CASE WHEN _left_join THEN 'LEFT JOIN' ELSE 'JOIN' END
, CASE WHEN _where_name <> '' THEN 'WHERE p.name LIKE $1' ELSE '' END
);
-- debug -- quote when tested ok
-- RAISE NOTICE '%', _sql;
-- execute -- unquote when tested ok
RETURN QUERY EXECUTE _sql
USING _where_name; -- $1
END
$func$ LANGUAGE plpgsql;
कॉल करें:
SELECT * FROM f_demo();
SELECT * FROM f_demo('sum', TRUE, '%2');
SELECT * FROM f_demo('avg', FALSE);
SELECT * FROM f_demo(_where_name := '%1_'); -- named param
-
आपको PL/pgSQL की पक्की समझ की आवश्यकता है। वरना समझाने के लिए बहुत कुछ है। आपको संबंधित उत्तर यहां SO पर plpgsql के अंतर्गत मिलेंगे। उत्तर में व्यावहारिक रूप से हर विवरण के लिए।
-
सभी मापदंडों का सुरक्षित रूप से इलाज किया जाता है, कोई SQL इंजेक्शन संभव नहीं है। अधिक:
-
विशेष रूप से ध्यान दें, कैसे एक
WHERE
क्लॉज सशर्त रूप से जोड़ा जाता है (जब_where_name
पास हो गया है) स्थितीय पैरामीटर के साथ$1
क्वेरी स्टिंग में। मानEXECUTE
. को पास किया जाता है मूल्य के रूप मेंउपयोग
खंड . कोई प्रकार का रूपांतरण नहीं, कोई पलायन नहीं, SQL इंजेक्शन का कोई मौका नहीं। उदाहरण: -
डिफ़ॉल्ट
का उपयोग करें फ़ंक्शन पैरामीटर के लिए मान, इसलिए आप कोई भी या कोई भी प्रदान करने के लिए स्वतंत्र हैं। अधिक: -
फ़ंक्शन
format ()
एक सुरक्षित और स्वच्छ फैशन में जटिल गतिशील SQL स्ट्रिंग्स के निर्माण के लिए महत्वपूर्ण है।