今天我们要结束在PostgreSQL数组世界的有趣旅程。今天的主题——你可能会遇到的典型错误,以及最重要的,怎么避免它们。如果你曾经想过“这个数组又在搞怪了”,那这节课就是为你准备的。来,一起搞明白吧。
创建数组时的错误:数组内数据类型问题
在PostgreSQL里创建数组时,记住所有元素必须是同一种类型。比如:
SELECT ARRAY[1, 2, '三'];
-- 错误:数组里的元素必须是同一种类型
PostgreSQL不允许你把数字和字符串混在一个数组里。如果你真的需要这样,记得做类型转换:
SELECT ARRAY[1::TEXT, 2::TEXT, '三'];
-- 现在数组全是字符串了
用ARRAY[]时数据类型不一致的错误
默认情况下,PostgreSQL会根据数组内容猜类型。如果你给了它模棱两可的数据,准备好报错吧:
SELECT ARRAY[1, NULL];
-- 错误:PostgreSQL不知道怎么解释NULL
解决方法是,明确指定数据类型:
SELECT ARRAY[1, NULL]::INTEGER[];
-- 现在一切正常
取数据时的错误:数组索引问题
如果你习惯了Python或JavaScript那种从0开始的数组索引,PostgreSQL会让你小吃一惊。这里数组索引是从1开始的。
SELECT ARRAY[10, 20, 30][0];
-- 错误:索引必须从1开始
正确的写法:
SELECT ARRAY[10, 20, 30][1];
-- 结果:10
用函数取数组时的错误
像unnest()这样的函数,如果你没注意,它会把数组“拆开”成多行,容易搞混:
CREATE TEMP TABLE example (
id SERIAL PRIMARY KEY,
tags TEXT[]
);
INSERT INTO example (tags) VALUES (ARRAY['标签1', '标签2']), (ARRAY['标签3']);
SELECT unnest(tags) FROM example;
-- 结果:
-- 标签1
-- 标签2
-- 标签3
如果你想保留行的上下文(比如id),要把它加上:
SELECT id, unnest(tags) AS tag FROM example;
-- 结果:
-- id | tag
-- 1 | 标签1
-- 1 | 标签2
-- 2 | 标签3
数组过滤和比较时的错误
- 错误使用
@>、<@、&&操作符
这些操作符有各自的用途:
@>检查一个数组是否包含另一个数组。<@检查一个数组是否被包含在另一个数组里。&&检查两个数组是否有交集。
如果用错了,就会报错:
SELECT ARRAY[1, 2, 3] @> 2;
-- 错误:@>操作符只能用于数组
正确写法:
SELECT ARRAY[1, 2, 3] @> ARRAY[2];
-- 结果:true
- 没有索引导致性能问题
如果你经常用数组操作符,发现查询慢,很可能是忘了建索引。比如这样给数组建索引:
CREATE INDEX idx_tags ON example USING GIN (tags);
现在用@>和&&的查询会快很多。
修改数组时的错误
- 删除和添加值
array_remove()和array_append()这些函数不会“原地”改数组,而是返回新数组。如果你以为原数组会变,那就错了:
UPDATE example
SET tags = array_remove(tags, '标签1');
-- 现在数组被更新了
如果你忘了写SET tags =,SQL会执行,但数组不会变。
- 用
array_append()时数据重复
array_append()不会检查元素是否已存在,可能会导致重复:
SELECT array_append(ARRAY['标签1', '标签2'], '标签1');
-- 结果:{标签1, 标签2, 标签1}
如果你想避免重复,可以先过滤:
SELECT array_remove(array_append(ARRAY['标签1', '标签2'], '标签1'), '标签1') || '标签1';
-- 结果:{标签1, 标签2}
防止错误的小建议
想避免上面这些数组相关的坑:
- 检查数据类型。如果有歧义,记得明确指定数组类型。
- 注意索引。PostgreSQL数组索引是从1开始的。
- 优化数组查询。用索引让比较和过滤更快。
- 先用小数据测试。如果数组查询慢,先用小数据集找瓶颈。
- 防止重复。加元素时多做一步检查,避免重复。
PostgreSQL里的数组就像一把利器,用得好很强大,但也要小心。照着这些建议来,你的数组再也不会让你熬夜(嗯,基本不会)。祝你数据库设计和优化顺利!
GO TO FULL VERSION