ในขณะที่พูดคุยโซลูชัน CTE แบบเรียกซ้ำสำหรับคำถามนี้:
@ypercubeพบข้อผิดพลาดที่น่าแปลกใจซึ่งทำให้เราตรวจสอบการจัดการกับตัวดัดแปลงประเภท เราพบพฤติกรรมที่น่าประหลาดใจ
1. Type cast ยังคงประเภทโมดิฟายเออร์ในบางบริบท
แม้เมื่อสั่งไม่ให้ ตัวอย่างพื้นฐานที่สุด:
SELECT 'vc8'::varchar(8)::varchar
หนึ่งอาจคาดหวังvarchar
(ไม่มีตัวดัดแปลง) อย่างน้อยฉันจะ แต่ผลลัพธ์คือvarchar(8)
(พร้อมตัวดัดแปลง) กรณีที่เกี่ยวข้องจำนวนมากในซอด้านล่าง
2. การต่อข้อมูล Array สูญเสียโมดิฟายเออร์ในบริบทบางอย่าง
โดยไม่จำเป็นต้องใช้ดังนั้นข้อผิดพลาดนี้อยู่ฝั่งตรงข้าม:
SELECT ARRAY['vc8']::varchar(8)[]
, ARRAY['vc8']::varchar(8)[] || 'vc8'::varchar(8)
นิพจน์แรกให้ผลvarchar(8)[]
ตามที่คาดไว้
แต่ข้อที่ 2 หลังจากการต่อข้อมูลอื่นvarchar(8)
จะถูกรดน้ำลงไปเพียงvarchar[]
(ไม่มีตัวปรับแต่ง) พฤติกรรมที่คล้ายกันจากarray_append()
ตัวอย่างในซอด้านล่าง
ทั้งหมดนี้ไม่สำคัญในบริบทส่วนใหญ่ Postgres จะไม่สูญเสียข้อมูลและเมื่อกำหนดให้กับคอลัมน์ค่าจะถูกบังคับให้เป็นประเภทที่ถูกต้องอย่างไรก็ตาม อย่างไรก็ตามการทำผิดในทิศทางตรงกันข้ามจะทำให้เกิดข้อยกเว้นที่น่าประหลาดใจ:
3. Recursive CTE ต้องการประเภทข้อมูลให้ตรงกัน
รับตารางง่ายนี้
CREATE TABLE a (
vc8 varchar(8) -- with modifier
, vc varchar -- without
);
INSERT INTO a VALUES ('a', 'a'), ('bb', 'bb');
ขณะที่ rCTE นี้ใช้งานได้กับvarchar
คอลัมน์vc
แต่ล้มเหลวสำหรับvarchar(8)
คอลัมน์vc8
:
WITH RECURSIVE cte AS (
(
SELECT ARRAY[vc8] AS arr -- produces varchar(8)[]
FROM a
ORDER BY vc8
LIMIT 1
)
UNION ALL
(
SELECT a.vc8 || c.arr -- produces varchar[] !!
FROM cte c
JOIN a ON a.vc8 > c.arr[1]
ORDER BY vc8
LIMIT 1
)
)
TABLE cte;
ข้อผิดพลาด: ข้อความค้นหาแบบเรียกซ้ำ "cte" คอลัมน์ 1 มีประเภทอักขระที่หลากหลาย (8) [] ในระยะที่ไม่ใช่แบบเรียกซ้ำ แต่เป็นประเภทอักขระที่หลากหลาย [] โดยรวม คำแนะนำ: ส่งเอาต์พุตของคำที่ไม่เกิดซ้ำไปเป็นชนิดที่ถูกต้อง ตำแหน่ง: 103
text
หนึ่งวิธีแก้ปัญหาอย่างรวดเร็วจะโยน
UNION
แบบสอบถามธรรมดาไม่แสดงปัญหาเดียวกัน: มันจะตัดสินสำหรับชนิดที่ไม่มีตัวแก้ไขซึ่งรับประกันว่าจะรักษาข้อมูลทั้งหมด แต่ rCTE นั้นพิถีพิถันมากกว่า
นอกจากนี้คุณจะไม่ประสบปัญหากับการใช้งานที่บ่อยขึ้นmax(vc8)
แทนORDER BY
/ LIMIT 1
, เพราะmax()
และเพื่อน ๆ จะตกลงtext
กันทันที (หรือประเภทฐานที่เกี่ยวข้องโดยไม่มีการแก้ไข)
SQL Fiddleแสดง 3 สิ่ง:
- ช่วงของนิพจน์ตัวอย่างรวมถึงผลลัพธ์ที่น่าประหลาดใจ
- rCTE ง่าย ๆ ที่ทำงานกับ
varchar
(ไม่มีตัวแก้ไข) - rCTE เดียวกันกำลังเพิ่มข้อยกเว้นสำหรับ
varchar(n)
(พร้อมตัวดัดแปลง)
ซอเป็นสำหรับ pg 9.3 ฉันได้รับผลลัพธ์เดียวกันในเครื่องสำหรับ pg 9.4.4
ฉันสร้างตารางจากนิพจน์การสาธิตเพื่อให้สามารถแสดงชนิดข้อมูลที่แน่นอนรวมถึงตัวแก้ไข ในขณะที่ pgAdmin แสดงข้อมูลนี้นอกกรอบมันไม่สามารถใช้งานได้จาก sqlfiddle ที่น่าทึ่งก็ยังไม่สามารถใช้ได้ในpsql
(!) สิ่งนี้เป็นที่รู้จักกันดีใน psql และมีการพูดถึงวิธีแก้ปัญหาที่เป็นไปได้ใน pgsql-hackers มาก่อนแต่ยังไม่ได้นำมาใช้ นี่อาจเป็นหนึ่งในสาเหตุที่ยังไม่ได้ตรวจพบและแก้ไขปัญหา
ในระดับ SQL คุณสามารถใช้pg_typeof()
เพื่อรับชนิด (แต่ไม่ใช่ตัวดัดแปลง)
คำถาม
เมื่อรวมกันแล้วทั้งสามประเด็นก็เลอะเทอะ
เพื่อความแม่นยำประเด็นที่1ไม่ได้เกี่ยวข้องโดยตรง แต่เป็นการทำลายการแก้ไขที่เห็นได้ชัดโดยนักแสดงในระยะที่ไม่เกิดซ้ำ: ARRAY[vc8]::varchar[]
หรือคล้ายกันซึ่งเพิ่มความสับสน
รายการใดบ้างที่เป็นข้อผิดพลาดความผิดพลาดหรือสิ่งที่ควรจะเป็น
ฉันทำอะไรบางอย่างขาดหายไปหรือเราควรรายงานข้อผิดพลาด?
UNION
สืบค้นแบบง่าย เป็นไปได้ไหมที่เราพบบั๊กอิสระสามตัวพร้อมกัน? (หลังจากเดือนและเดือนที่ไม่มีการค้นพบเช่นนั้น) คุณควรจะยื่นข้อใดเป็นข้อผิดพลาด?