ใช้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ตัวเลขโดยอัตโนมัติและทุกอย่างก็เข้าที่