10个PostgreSQL中常见SQL错误

本文涉及的产品
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS SQL Server,基础系列 2核4GB
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: QL语言当今在数据查询分析这块地位至今无法撼动,曾经的NoSQL也开始疲软,口号从”no SQL”也变成了“not only SQL”或“no , SQL!”, 但SQL的开发能力参差不齐,有些是从ORACLE数据库转到postgreSQL的,相同SQL的结果不并相同,在性能上也并不是所有人都可以编写高效正确查询,这里简单列几个在PG中几个SQL注意事项。

SQL语言当今在数据查询分析这块地位至今无法撼动,曾经的NoSQL也开始疲软,口号从”no SQL”也变成了“not only SQL”或“no , SQL!”, 但SQL的开发能力参差不齐,有些是从ORACLE数据库转到postgreSQL的,相同SQL的结果不并相同,在性能上也并不是所有人都可以编写高效正确查询,这里简单列几个在PG中几个SQL注意事项。

1,除以整数得整数

# oracle

select 1/3 value from dual;

value

-----------------------------------------

.3333333333333333333333333333333333333333


# PostgreSQL

select 1/3 as value ;

value

----------

0


在postgresql中如果想要得到除法预期结果,需要把其中一个转换为浮点数

select 1/3::float as value

value

-------------------

0.3333333333333333


2, 除数为0

在其它数据库中也一样,除数据不可以为0

select 2/0 as value;

ERROR:  division by zero


分母不可以为0这是一个算数要求,在写SQL时需要避免,可以当分母为0时返回null(如果第一个参数等于第二个参数,则函数 NULLIF 返回 null。)或-1(COALESCE该函数返回其第一个不为 null 的参数)等特定值,同样适用于oracle(nvl函数).

SELECT 1 / NULLIF(0, 0) as value;

value

--------------------

null


SELECT COALESCE(1 / NULLIF(0, 0), -1) as value;

value

---------

-1


3, union与union all

union相比union all增加了排除重复行,如果不需要排除重复行,出于性能考虑最好使用union all

explain analyze

select padding from t1

union

select padding from t2;


HashAggregate  (cost=754.74..968.10 rows=21336 width=32) (actual time=9.343..10.560 rows=10000 loops=1)

Group Key: t1.padding

 Batches: 1  Memory Usage: 1809kB

 ->  Append  (cost=0.00..701.40 rows=21336 width=32) (actual time=0.017..4.587 rows=20000 loops=1)

       ->  Seq Scan on t1  (cost=0.00..190.68 rows=10668 width=32) (actual time=0.016..1.576 rows=10000 loops=1)

       ->  Seq Scan on t2  (cost=0.00..190.68 rows=10668 width=32) (actual time=0.011..1.488 rows=10000 loops=1)

Planning Time: 0.147 ms

Execution Time: 11.632 ms



explain analyze

select padding from t1

union all

select padding from t2;


Append  (cost=0.00..488.04 rows=21336 width=32) (actual time=0.018..4.418 rows=20000 loops=1)

 ->  Seq Scan on t1  (cost=0.00..190.68 rows=10668 width=32) (actual time=0.017..1.502 rows=10000 loops=1)

 ->  Seq Scan on t2  (cost=0.00..190.68 rows=10668 width=32) (actual time=0.011..1.469 rows=10000 loops=1)

Planning Time: 0.144 ms

Execution Time: 5.131 ms



note:

在有些时时候union 执行计划可能不是HashAggregate 而是sort unique.

4, count可为null列

使用聚合函数对可为null的列运算时需要注意,如count(col)

create table t1 (id int, padding text);


insert into t1 (id, padding)

   select id, md5(random()::text)

   from generate_series(1, 10) as id

   order by random();


insert into t1 values(1,null);


select count(padding) cntp,count(*) cnt from t1;

cntp cnt

-----   -----

10 11


note:

Null在统计行记录数时会忽略.

5, 日期to_date 不带时分秒

oracle的to_date函数比postgresql的多时分秒,我们一个项目中从oracle迁移过来的, 每隔5分钟一个批次插入数,同时以时间列判断这一批是否已存在。迁移到postgresql后发现入库的数据总比oracle少,但程序无报错,后分析每天只入了第一批,因为postgresql的to_date只精确到天。之前我的blog记录过<Oracle迁移到PostgreSQL注意事项: to_date>

select to_date('2023-1-1 12:13:14','yyyy-mm-dd hh24:mi:ss')

to_date

----------

2023-01-01


可以写成

select to_timestamp('2023-1-1 12:13:14','yyyy-mm-dd hh24:mi:ss')


或配置orafce重载to_date。


6, 时区

时区问题有可能在时间截断为天时,跨了天产生错误数据,尤其是全球化业务, 如存储created_at的是timestamp,转换为date统计每天的数据时.

SELECT created_at::date, COUNT(*)

FROM sale

GROUP BY 1;


SHOW timezone;

TimeZone

-------

GB


select (now()+ interval '15 H')::date;

date

----------

2023-05-31


SET TIME ZONE  'Asia/Shanghai'


select (now()+ interval '15 H')::date;

date

-----------

2023-06-01


统计转date时可以带上timezone,如

SELECT (now() at time zone 'Asia/Shanghai')::date;



Note:

要在 PostgreSQL 中获取时区名称的完整列表,请查询视图pg_timezone_names

7, between 范围

between 的时间过滤是包含性的,等同于>= and <=, 有时你可能只想统计某月份的。

select * from xx

where created between '2023-5-1' and  '2023-6-1';

这是错误的,等效于

select * from xx

where created>='2023-5-1' and  created<='2023-6-1'; 而如果你只要202305月份应该是 select * from xx where created>='2023-5-1' and  created<'2023-6-1';

-- or --

select * from xx

where created between '2023-5-1' and  '2023-5-31';


8, 索引列转换

这一点和oracle一样,不建议在已创建的索引列上使用转换或函数,容易导致索引无法使用。

where id::float < 5;

虽然id列有索引也无法使用,改为右侧转换如:

where id < 5.0::int;


9, WITH子名

在 PostgreSQL 12 之前的版本中,当 with使用不当时,它们可能会导致内存使用量增加和性能下降, with 会创建一个临时结构,如果你是个oracle DBA,它就像是 with 加了/*+materialize*/ 物化的hint,在多次引用时可以避免冗余多次评估,听上去很不错,但是它像硬币的的另一面可能不能view展开,主查询的谓词无法推进到with中。 但是从postgresql 12改变处理方式.

create table foo (id int, padding text);


insert into foo (id, padding)

   select id, md5(random()::text)

   from generate_series(1, 1000000) as id

   order by random();


create index foo_id_ix on foo (id);


explain (analyze on, timing on)

with cte as (

   select * from foo

)

select * from cte where id = 500000;


# posgresql 11

QUERY PLAN

CTE Scan on cte  (cost=18334.00..40834.00 rows=5000 width=36) (actual time=392.819..422.508 rows=1 loops=1)

 Filter: (id = 500000)

 Rows Removed by Filter: 999999

 CTE cte

   ->  Seq Scan on foo  (cost=0.00..18334.00 rows=1000000 width=37) (actual time=0.021..146.183 rows=1000000 loops=1)

Planning Time: 0.201 ms

Execution Time: 427.964 ms


# postgresql 12+

QUERY PLAN

Index Scan using foo_id_ix on foo  (cost=0.42..8.44 rows=1 width=37) (actual time=0.045..0.046 rows=1 loops=1)

 Index Cond: (id = 500000)

Planning Time: 0.245 ms

Execution Time: 0.077 ms



10,  字符串拼接

‘char’||null在oracle为char,但在postgresql为null

# oracle

select 'char'||null newv from dual;

NEWW

---------

char


# postgresql

select 'char'||null newv;

newv

--------

null


— over —


相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍如何基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
2月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS费用价格:MySQL、SQL Server、PostgreSQL和MariaDB引擎收费标准
阿里云RDS数据库支持MySQL、SQL Server、PostgreSQL、MariaDB,多种引擎优惠上线!MySQL倚天版88元/年,SQL Server 2核4G仅299元/年,PostgreSQL 227元/年起。高可用、可弹性伸缩,安全稳定。详情见官网活动页。
|
2月前
|
关系型数据库 分布式数据库 数据库
阿里云数据库收费价格:MySQL、PostgreSQL、SQL Server和MariaDB引擎费用整理
阿里云数据库提供多种类型,包括关系型与NoSQL,主流如PolarDB、RDS MySQL/PostgreSQL、Redis等。价格低至21元/月起,支持按需付费与优惠套餐,适用于各类应用场景。
|
5月前
|
SQL 关系型数据库 MySQL
Go语言数据库编程:使用 `database/sql` 与 MySQL/PostgreSQL
Go语言通过`database/sql`标准库提供统一数据库操作接口,支持MySQL、PostgreSQL等多种数据库。本文介绍了驱动安装、连接数据库、基本增删改查操作、预处理语句、事务处理及错误管理等内容,涵盖实际开发中常用的技巧与注意事项,适合快速掌握Go语言数据库编程基础。
470 62
|
2月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎,提供高性价比、稳定安全的云数据库服务,适用于多种行业与业务场景。
|
5月前
|
SQL 关系型数据库 PostgreSQL
CTE vs 子查询:深入拆解PostgreSQL复杂SQL的隐藏性能差异
本文深入探讨了PostgreSQL中CTE(公共表表达式)与子查询的选择对SQL性能的影响。通过分析两者底层机制,揭示CTE的物化特性及子查询的优化融合优势,并结合多场景案例对比执行效率。最终给出决策指南,帮助开发者根据数据量、引用次数和复杂度选择最优方案,同时提供高级优化技巧和版本演进建议,助力SQL性能调优。
570 1
|
9月前
|
SQL 关系型数据库 OLAP
云原生数据仓库AnalyticDB PostgreSQL同一个SQL可以实现向量索引、全文索引GIN、普通索引BTREE混合查询,简化业务实现逻辑、提升查询性能
本文档介绍了如何在AnalyticDB for PostgreSQL中创建表、向量索引及混合检索的实现步骤。主要内容包括:创建`articles`表并设置向量存储格式,创建ANN向量索引,为表增加`username`和`time`列,建立BTREE索引和GIN全文检索索引,并展示了查询结果。参考文档提供了详细的SQL语句和配置说明。
285 2
|
SQL 关系型数据库 C语言
PostgreSQL SQL扩展 ---- C语言函数(三)
可以用C(或者与C兼容,比如C++)语言编写用户自定义函数(User-defined functions)。这些函数被编译到动态可加载目标文件(也称为共享库)中并被守护进程加载到服务中。“C语言函数”与“内部函数”的区别就在于动态加载这个特性,二者的实际编码约定本质上是相同的(因此,标准的内部函数库为用户自定义C语言函数提供了丰富的示例代码)
|
SQL 存储 关系型数据库
PostgreSQL核心之SQL基础学习
PostgreSQL核心之SQL基础学习
357 3
|
SQL 安全 关系型数据库
PostgreSQL SQL注入漏洞(CVE-2018-10915)--处理
【8月更文挑战第8天】漏洞描述:PostgreSQL是一款自由的对象关系型数据库管理系统,支持多种SQL标准及特性。存在SQL注入漏洞,源于应用未有效验证外部输入的SQL语句,允许攻击者执行非法命令。受影响版本包括10.5及更早版本等。解决方法为升级PostgreSQL
751 2
|
SQL 关系型数据库 MySQL
SQL Server、MySQL、PostgreSQL:主流数据库SQL语法异同比较——深入探讨数据类型、分页查询、表创建与数据插入、函数和索引等关键语法差异,为跨数据库开发提供实用指导
【8月更文挑战第31天】SQL Server、MySQL和PostgreSQL是当今最流行的关系型数据库管理系统,均使用SQL作为查询语言,但在语法和功能实现上存在差异。本文将比较它们在数据类型、分页查询、创建和插入数据以及函数和索引等方面的异同,帮助开发者更好地理解和使用这些数据库。尽管它们共用SQL语言,但每个系统都有独特的语法规则,了解这些差异有助于提升开发效率和项目成功率。
1565 0

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版