1. 程式人生 > 其它 >PostgreSql和MySql資料型別之間的比較以及推薦

PostgreSql和MySql資料型別之間的比較以及推薦

文章介紹了 postgresql 和 MySql 之間資料型別的比較,以及推薦使用。因為存在資料庫表遷移等場景,會更需要此類情況的對比

1. 數值型別的比較

整數:

mysql中的整數型別和 pg 相比,兩者有以下區別:

  • mysql:mysql中支援int 1,2,3,4,8 位元組,同時支援有符號,無符號。並且mysql中支援在數值列中指定zerofill,用來將儲存的數值通過填充0的方式達到指定資料型別的長度(mysql8開始不建議使用ZEROFILL屬性,並且在將來的MySQL版本中將不再支援該屬性)。

  • pg:pg支援 int 2,4,8 位元組,且數值都是有符號的。

mysql整數型別:

pg整數型別:

那麼對於mysql中的1,3位元組整型,或者無符號整型以及zerofill特性,在pg中該如何實現呢?

在pg中我們可以使用domain來實現mysql中的1,3位元組整數以及無符號整型。

建立uint8,8位元組無符號整型

bill=# create domain uint8 as numeric(20,0) check (value <= ((2^64::numeric)::numeric(20,0)-1) and value>=0::numeric(20,0)); 
CREATE DOMAIN

使用domain,插入整型資料,且大於等於0,小於2^64

bill=# create table t5(c1 uint8); 
CREATE TABLE
bill=# insert into t5 values (-1);
ERROR: value for domain uint8 violates check constraint "uint8_check"
bill=# insert into t5 values (0); 
INSERT 0 1
bill=# insert into t5 values (18446744073709551615); 
INSERT 0 1
bill=# insert into t5 values (18446744073709551616); 
ERROR: value for domain uint8 violates check constraint "uint8_check"
bill=# select * from t5; 
  c1  
----------------------
   0
 18446744073709551615
(2 rows)

同樣我們也可以來建立domain實現1,3位元組有無符號整型,2,4,8位元組無符號等等:

create domain int1 as int2 CHECK (VALUE <= 127 AND VALUE >= (-128)); 
create domain uint1 as int2 CHECK (VALUE <= 255 AND VALUE >= 0); 
create domain uint2 as int4 CHECK (VALUE <= 65535 AND VALUE >= 0); 
create domain int3 as int4 CHECK (VALUE <= 8388607 AND VALUE >= (-8388608)); 
create domain uint3 as int4 CHECK (VALUE <= 16777215 AND VALUE >= 0); 
create domain uint4 as int8 CHECK (VALUE <= 4294967295 AND VALUE >= 0); 
create domain uint8 as numeric(20,0) check (value <= ((2^64::numeric)::numeric(20,0)-1) and value>=0::numeric(20,0)); 

而對於mysql中的zerofill,我們可以使用lpad函式來實現,並且這也是mysql官方文件中推薦的一種方式。

mysql中zerofill使用方式:

mysql> create table t1(id int1 zerofill); 
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t1 values(4);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t1;
+------+
' id '
+------+
' 004 '
+------+
1 row in set (0.00 sec)

pg中使用lpad函式替代:

bill=# create table t1(id int); 
CREATE TABLE
bill=# insert into t1 values (123),(123456); 
INSERT 0 2
bill=# select lpad(id::text, greatest(4, length(id::text)), '0'), id from t1; 
 lpad ' id 
--------+--------
 0123 ' 123
 123456 ' 123456
(2 rows)

numeric型別:

pg和mysql一樣都支援decimal,numeric型別來表示浮點數。兩者的區別在於:mysql中的numeric型別整數和小數部分均最大支援65digits。

而pg中numeric型別支援的最大範圍是:

[左131072,右16383]digits。

例如:

  • mysql中

    mysql> create table t1(id numeric(66,1));
    ERROR 1426 (42000): Too-big precision 66 specified for 'id'. Maximum is 65.
    mysql> create table t1(id numeric(65,1)); Query OK, 0 rows affected (0.01 sec)

  • pg中

    bill=# create table t4(id numeric(66,1)); CREATE TABLE

浮點型別:

mysql和pg中的浮點數型別基本一致。mysql中4 bytes的浮點數型別有real,float4,4 bytes的浮點數型別double。pg中對應的也有real,float,float4,float8以及double precision,兩者基本相容。

bit型別:

mysql中bit型別一般都是使用整數型別表示,所以支援的bit位數最大隻能是64位。而在pg中有專門的bit型別bit(範圍1~83886080),以及可變長度的bit型別varbit。

序列:

mysql中建立表時可以使用auto_increment來建立自增列,從而生成一個和該列相關的序列,這個和pg中建立serial型別的列類似,但是兩者仍然有明顯區別:

mysql:使用auto_increment的自增列必須要建索引,不然會報錯。序列的預設初始值是1,步長為1.可以通過修改auto_increment_increment和auto_increment_offset來修改初始值和步長。

pg:pg中建立serial型別的列時會建立相應的序列,支援的資料型別有serial2,serial4,serial8。同時pg建立序列時可以直接指定初始值,步長,maxvalue,cache,circle等引數。其中序列cache預取多個值,可以保證沒有效能問題。circle可以指定序列達到最大值後從初始值開始重新計數。

  • mysql

    mysql> create table t4 (id int auto_increment primary key);
    

    Query OK, 0 rows affected (0.06 sec)

  • PostgreSQL

    bill=# create table t4(id serial);
    

    CREATE TABLE

2. 時間型別

  • mysql:mysql中時間相關的型別有日期date、時間time以及datetime、timestamp和year型別。

  • pg:pg中的時間資料型別基本和mysql一致。區別在於pg中支援timez型別,即帶時區的時間型別,這個mysql中不支援,但是pg中不支援mysql中的year型別,不過我們仍然可以通過建立domain的方式來在pg中實現year型別。

  • mysql中的year型別表示年份從 1901年到2155。

  • pg中實現mysql中year型別的方式:

    bill=# create domain year as int2 check(value >=1901 and value <=2155);    CREATE DOMAIN
    

    bill=# create table ts4(c1 year); CREATE TABLE
    bill=# insert into ts4 values (1000);
    ERROR: value for domain year violates check constraint "year_check"
    bill=# insert into ts4 values (2019);
    INSERT 0 1
    bill=# insert into ts4 values (2156);
    ERROR: value for domain year violates check constraint "year_check"

3. 字串型別

char/varchar型別:

  • mysqlpg 中都支援char型別來表示固定長度的字串,varchar型別表示可變長度的字串型別,兩者的區別在於:

  • mysql:char型別最大255字元,varchar型別最大不超過64位元組。

  • pg:char型別最大10485760字元,varchar型別最大1G位元組。同時pg中還支援兩種特殊的字串型別:name型別,固定64位元組長度,char型別(即不指定長度),固定1位元組長度。

binary/varbinary型別:

mysql 中binary(n)最大255個字元,varbinary(n)最大不超過64k位元組。使用位元組流來儲存字串。而 pg 中使用bytea型別來表示二進位制型別,最大不超過1G位元組。

blob/text型別:

  • mysql 中的blob/text型別分別有以下幾種:
    tinyblob、tinytext < 2^8位元組
    blob、text < 2^16位元組
    mediumblob、mediumtext < 2^24位元組
    longblob、longtext < 2^32位元組

  • pg 中對應的使用bytea型別和text型別,兩者最大長度均為1G位元組。

enum型別:

mysql中的列舉型別最大不超過64K個值,而pg中最大為1GB

set型別:

mysql中的集合set型別表示沒有重複值的集合,最大64個值,在pg中雖然沒有set型別,但是可以通過陣列型別去代替,最大支援1GB大小。

3、其它型別

json型別:

  • mysql和pg中的json型別基本一致,區別在於默寫json函式可能稍有區別。不過pg中json型別有2種json和jsonb,不過一般都使用jsonb型別。

  • 除了上面列舉的這些型別之外,pg中還支援很多mysql中不支援的資料型別。例如:pg中支援IP地址型別,這個在mysql中常常都是使用int或者varchar之類的資料型別代替。

  • 除此之外還有很多pg內建的資料型別在mysql中是不支援的:貨幣、interval、平面幾何、全文檢索、uuid、xml、陣列、複合型別、範圍型別、域型別等等。

  • 同時pg還有很多外接的資料型別:樹型別、多維型別、化學分子、DNA、postgis等等型別。

補充:Oracle與PostgreSQL使用差異對比與總結

JDBC連線:

Oracle的jdbc連線字串:db.url=jdbc:oracle:thin:@192.168.1.1:1521:ORCL

Postgresql的連線字串:db.url=jdbc:postgresql:@192.168.1.1:5432/database

1、 基本資料型別差異

Oracle PostgreSQL
Varchar2 varchar
number numeric
date timestamp/date/time
不支援boolean,可通過0/1代替 支援boolean
null null

2、 基本函式差異

item Oracle PostgreSQL
系統當前時間 SYSDATE now()/CURRENT_TIMESTAMP/CURRENT_DATE/CURRENT_TIME
對時間或數字擷取 trunc() date_trunc()
to_char,to_number, to_date 自動格式轉換 需指定日期格式 eg:to_date(timejoin,'yyyy-MM-dd')
判空操作 nvl() coalesce()
條件判斷 decode() case...when...then
dual偽表 支援 不支援(查詢常量不需要加from)

其他用法一致的常用函式:

  • mod(n2,n1) -- n2除n1取餘數; sign(n) -- 判斷n的符號;

  • floor(n) -- 取小於等於n的正整數; ceil() -- 取大於等於n的正整數;

  • round(n,integer) -- 對n四捨五入,保留位數為integer; trunc(n,integer) -- 對n擷取,擷取保留的位數為integer;

  • covert(char,dest_sest,source_set) -- 字符集轉換,例:convert(username, 'ZHS16GBK','UTF8');

  • cast(expr as type_name) -- 資料型別轉換,常用於數字與字元間轉換,例:cast(id_no as varchar);

部分函式的使用簡析:

(1)coalesce(COL1,COL2,COL3):返回引數中第一個非null欄位值

例如:coalesce(COL1,0):如果COL1為null或'',則返回預設值0;否則返回COL1的值;

(2)extract(date):對日期特定部分提取(oracle和postgresql使用一致)

例如:

extract(year from now());>>>2018
extract(month from now());>>>9
extract(month from timestamp '2018-09-10 13:59:59');>>>9

(3)對時間擷取trunc()和date_trunc()

oracle--trunc()的用法:

trunc(sysdate,'yyyy');//返回當前年的第一天>>>2018-01-01
trunc(sysdate, 'mm');//返回當前月的第一天>>>2018-09-01
trunc(sysdate, 'dd');//返回當前時間的年月日>>>2018-09-14
trunc(sysdate, 'hh');//返回當前小時>>>2018-09-14 13:30:50

postgreSQL--date_trunc()用法:

date_trunc('year',now());//返回當前時間年的第一天>>>2018-01-01 00:00:00
date_trunc('month',now());//返回當前月的第一天>>2018-09-01 00:00:00
date_trunc('day',now()); //返回當前時間的年月日>>2018-09-14 00:00:00  
date_trunc('second',now()); //返回當前時間的年月日時分秒>>2018-09-14 13:30:50 

(4)條件判斷

Oracle:
 Select DECODE (payments_info,'CR','Credit','DB','Debit', null) FROM dual;
PostgreSQL:
 Select CASE
 WHEN foo = 'CR' THEN 'Credit'
 WHEN foo = 'DB' THEN 'Debit'
 ELSE 'default'
 END
 FROM t2;

3、DDL語法差異

oracle和pgSQL操作表結構語法基本一致:

修改表名:alter table tbl_user rename tbl_user2;

新增約束:alter table 表名 add constraint 表名_列名_nn check (is not null)

新增列:alter table tbl_user add age number(3) default 18 not null;

alter table tbl_user add age number(3) default 18 not null after sex;(在指定列後新增列)

刪除列:alter table tbl_user drop column age;

修改列:alter table tbl_user modify password default'000000' not null;(修改約束)

修改列名:alter table tbl_user rename column password to pwd;

只有更改列的資料型別寫法有些差異

Oracle:ALTER TABLE table_name modify column_name datatype;

PostgreSQL:ALTER TABLE table_name ALTER column_name TYPE datatype;

4、DML語法差異

oracle和pgSQL增刪改查語法基本一致,只有upsert有差異

Oracle:有自帶的merge into功能(一個強大的操作)

  • PostgreSQL:不支援merge操作,可以使用on conflict() do
    例:

    insert into TargetTable

    select id,desc

    from SourceTable

    on conflict (id)

    do update set

    desc = exclude.desc

5、查詢語句差異

(1)查詢表中最新n條資料(Oracle有rownum,postgreSQL有limit)

postgreSQL:

select * from olc.olc_member_intebid_info order by create_time desc limit n;

注意:limit必須用於 order by 之後

Oracle:

寫法一:

select t.* from (select * from nwd.tc_inte_bid_record order by create_time desc) t where rownum <= n;

寫法二:

select * from(select t.*, row_number() over(order by create_time desc) rn from nwd.tc_inte_bid_record t) where rn <=n;

上述寫法一為通用常規寫法;寫法二可以對分組後資料排序,分組語句寫在over()中

(2)子查詢

postgresql子查詢要求比較嚴格,必須具有別名才可以

6、 Postgresql命令列常用操作(psql)

psql -d dbname -U username -p 5210 -h 172.0.0.1

--password 's&cws123'

如果不想輸入密碼,可以在.pgpass隱藏檔案中新增密碼,格式:

172.0.0.1:5210:dbname:username:password

注意.pgpass的許可權問題:chmod 0600 ~/.pgpass

-- 查詢某個庫下的所有表(\dt)
select * from pg_tables where schemaname = 'idn_dw';

-- 查詢某個儲存過程(\df)
select proname,prosrc from pg_proc where proname = 'func_dwd_customer_info';

-- 查詢某個表下的欄位(\d tablen_ame)
select table_schema,table_name,t.colname,string_agg(column_name,',') as COLS 
from information_schema.columns
LEFT JOIN (select pg_class.relname as tablename,pg_attribute.attname as colname from
pg_constraint inner join pg_class
on pg_constraint.conrelid = pg_class.oid
inner join pg_attribute on pg_attribute.attrelid = pg_class.oid
and pg_attribute.attnum = pg_constraint.conkey[1]
where pg_constraint.contype='p') t
on table_name=t.tablename
where TABLE_NAME = 's10_anfd_rule'
group by table_schema,table_name,t.colname;