ใช้RETURN QUERY
:
CREATE OR REPLACE FUNCTION word_frequency(_max_tokens int)
RETURNS TABLE (txt text -- also visible as OUT parameter inside function
, cnt bigint
, ratio bigint) AS
$func$
BEGIN
RETURN QUERY
SELECT t.txt
, count(*) AS cnt -- column alias only visible inside
, (count(*) * 100) / _max_tokens -- I added brackets
FROM (
SELECT t.txt
FROM token t
WHERE t.chartype = 'ALPHABETIC'
LIMIT _max_tokens
) t
GROUP BY t.txt
ORDER BY cnt DESC; -- potential ambiguity
END
$func$ LANGUAGE plpgsql;
โทร:
SELECT * FROM word_frequency(123);
คำอธิบาย:
มันเป็นมากในทางปฏิบัติมากขึ้นอย่างชัดเจนกำหนดประเภทผลตอบแทนมากกว่าเพียงแค่การประกาศว่าเป็นบันทึก วิธีนี้ทำให้คุณไม่ต้องระบุรายการนิยามคอลัมน์ในทุกการเรียกใช้ฟังก์ชัน RETURNS TABLE
เป็นวิธีหนึ่งในการทำเช่นนั้น ยังมีคนอื่นอีก ประเภทข้อมูลของOUT
พารามิเตอร์ต้องตรงกับสิ่งที่ส่งกลับมาจากการสืบค้น
เลือกชื่อสำหรับOUT
พารามิเตอร์อย่างระมัดระวัง สามารถมองเห็นได้ในส่วนของฟังก์ชันเกือบทุกที่ คอลัมน์คุณสมบัติตารางที่มีชื่อเดียวกันเพื่อหลีกเลี่ยงความขัดแย้งหรือผลลัพธ์ที่ไม่คาดคิด ฉันทำเช่นนั้นสำหรับคอลัมน์ทั้งหมดในตัวอย่างของฉัน
แต่สังเกตความขัดแย้งในการตั้งชื่อที่อาจเกิดขึ้นระหว่างOUT
พารามิเตอร์cnt
และนามแฝงคอลัมน์ที่มีชื่อเดียวกัน ในกรณีนี้โดยเฉพาะ ( RETURN QUERY SELECT ...
) Postgres ใช้นามแฝงของคอลัมน์เหนือOUT
พารามิเตอร์ทางใดทางหนึ่ง สิ่งนี้อาจคลุมเครือในบริบทอื่น ๆ มีหลายวิธีในการหลีกเลี่ยงความสับสน:
- ใช้ตำแหน่งลำดับของรายการในรายการ SELECT
ORDER BY 2 DESC
นี้: ตัวอย่าง:
ORDER BY count(*)
ทำซ้ำการแสดงออก
- (ไม่สามารถใช้ได้ที่นี่) ตั้งค่าพารามิเตอร์การกำหนดค่า
plpgsql.variable_conflict
หรือใช้คำสั่งพิเศษ#variable_conflict error | use_variable | use_column
ในฟังก์ชัน ดู:
อย่าใช้ "text" หรือ "count" เป็นชื่อคอลัมน์ ทั้งสองอย่างถูกกฎหมายที่จะใช้ใน Postgres แต่ "count" เป็นคำสงวนใน SQL มาตรฐานและชื่อฟังก์ชันพื้นฐานและ "ข้อความ" เป็นชนิดข้อมูลพื้นฐาน อาจทำให้เกิดข้อผิดพลาดที่สับสน ฉันใช้txt
และcnt
ในตัวอย่างของฉัน
เพิ่ม;
ข้อผิดพลาดทางไวยากรณ์ที่ขาดหายไปและแก้ไขในส่วนหัว (_max_tokens int)
ไม่(int maxTokens)
- ประเภทหลังชื่อ
ในขณะที่ทำงานกับการหารจำนวนเต็มควรคูณก่อนแล้วหารในภายหลังเพื่อลดข้อผิดพลาดในการปัดเศษให้น้อยที่สุด ดียิ่งขึ้น: ทำงานกับnumeric
(หรือประเภทจุดลอยตัว) ดูด้านล่าง
ทางเลือก
นี่คือสิ่งที่ฉันคิดว่าข้อความค้นหาของคุณควรมีลักษณะดังนี้ (การคำนวณส่วนแบ่งสัมพัทธ์ต่อโทเค็น ):
CREATE OR REPLACE FUNCTION word_frequency(_max_tokens int)
RETURNS TABLE (txt text
, abs_cnt bigint
, relative_share numeric) AS
$func$
BEGIN
RETURN QUERY
SELECT t.txt, t.cnt
, round((t.cnt * 100) / (sum(t.cnt) OVER ()), 2) -- AS relative_share
FROM (
SELECT t.txt, count(*) AS cnt
FROM token t
WHERE t.chartype = 'ALPHABETIC'
GROUP BY t.txt
ORDER BY cnt DESC
LIMIT _max_tokens
) t
ORDER BY t.cnt DESC;
END
$func$ LANGUAGE plpgsql;
การแสดงออกsum(t.cnt) OVER ()
เป็นฟังก์ชั่นหน้าต่าง คุณสามารถใช้CTEแทนเคียวรีย่อยได้ แต่โดยทั่วไปแล้วคิวรีย่อยจะมีราคาถูกกว่าในกรณีง่ายๆเช่นนี้
ไม่จำเป็นต้องมีคำสั่งที่ชัดเจนRETURN
ขั้นสุดท้าย(แต่อนุญาต) เมื่อทำงานกับOUT
พารามิเตอร์หรือRETURNS TABLE
(ซึ่งใช้OUT
พารามิเตอร์โดยปริยาย)
round()
ด้วยพารามิเตอร์สองตัวที่ใช้ได้กับnumeric
ประเภทเท่านั้น count()
ในการสืบค้นย่อยจะสร้างbigint
ผลลัพธ์และสิ่งsum()
นี้bigint
จะสร้างnumeric
ผลลัพธ์ดังนั้นเราจึงจัดการกับnumeric
ตัวเลขโดยอัตโนมัติและทุกอย่างก็เข้าที่