oracle官方文档
《oracle编程艺术》,有深度
生产环境推荐使用percona
恒生学习
参数文件默认路径
- /etc/my.cnf等
参数分组
[mysqld]
[mysql_safe]:mysqld的守护进程
[client]
[mysqldump]:导数据
隔离级别
重要参数
- character_set_server,默认latin1
- collation_server,默认latin1_swdish_ci,根据字符集自动改变
- 8.0,字符集和排序规则需要添加,init_connect = “SET NAMES ‘utf8mb4’ COxxx”
- innodb log file
用户管理
忘记密码了:
--- 5.7之后的,需要写mysql-init
mysqld --init-file=/home/me/mysql-init &
备份
--- 全库
mysqldump -uroot -pxxx -A -F --single-transaction --triggers --events --routines > full_backup.sql
--- 指定数据库
mysqldump -uroot -pxxx -B db1,db2 -A -F --single-transaction --triggers --events --routines > db_backup.sql
-- 导出指定表
mysqldump -uroot -pxx -F -q --single-transaction db1 test > test.sql
--- 客户端导入数据
mysql > source db_backup.sql
--- 操作系统导入
mysql -uroot -pxxx < xxx.sql
表碎片
产生原因:
- 删除一行数据,该行数据不会立即释放,而是编程空白空间
- 插入数据时,尝试使用空白空间,数据小于空白空间,则形成碎片
解决方案
- optimize table tableName
- alter table tableName engine = innodb;
清理碎片会暂时锁表,数据量大时,时间长
统计信息收集
手动收集:analyze table tableName
自动收集:
- 第一次打开表
- 新的记录插入
- 表修改行超过1/6或20亿条
开启参数 innodb_stats_on_metadata
- 执行show table status
- 访问information_schema下的元数据表
binlog日志管理
-- 存在哪些binlog
show master/binary logs;
-- 清除
purge binary logs before 'yyyy-mm-dd hh24:mi:ss'
-- 自动清理
--- 设置expire_logs_days
冗余的索引
select table_schema, table_name, redundant_index_name, redundant_index_columns
from sys.schema_redundant_indexes;
常见信息查询
--- 线程列表
show processlist;
--- 复制状态
show slave status;
--- 最大连接数
show global status like 'max_used_connections'
表设计优化
自增ID或unsigned整型作为主键
禁止用外键,让应用实现
建议字段not null
不存放text、blob等大字段
金钱相关字段使用decimal
禁止存储过程,触发器、函数、视图、事件等高级功能
sql优化
慢查询日志设置
slow_query_log:慢查询是否开启
long_query_time:超过多长时间记录
slow_query_log_file:慢查询文件路径和名称
log_queries_not_using_indexes:是否有没使用索引的SQL
分析慢查询日志,mysqldumpslow
-- 执行次数最多的5条
mysqldumpslow -s -c -t 5 /mylog/my3306/slow.log
-- 返回记录最多的
mysqldumpslow -s -r -t 5 /mylog/my3306/slow.log
-- 执行时间最长的
mysqldumpslow -s t -t 5 /mylog/my3306/slow.log
语句优化
explain
- id:执行顺序
- table,输出结果集的表
- type,表的访问路径,连接类型
- filterd,过滤百分比
- rows扫描出的行数
- possible_key,可能使用的索引
- key,实际使用的索引
- ref,进行关联的字段
- 禁止使用 select *
- 所有表有主键
- 禁止使用find_in_set、instr函数
- 生产状态下禁止大事务,要求单事务数据控制在10万条以内
---
select xxx limit 50000,5000;
--- 优化
select *
from (select no from xxx limit 250000,5000) b, employees a
where a.xxx = b.xxx
--- union 优化
union all
--- union 去重并排序,union all 直接返回合并的结果,不去重也不排序
--- union all比 union 性能好
乱码
存入和取出编码不一致
两个字符集之间无法无损装换
解决:
- 确保客户端编码格式
- mysql编码格式
字段类型
数值类型
类型 | 大小 | 范围(有符号) | 范围(无符号) | 用途 |
---|---|---|---|---|
TINYINT | 1 Bytes | (-128,127) | (0,255) | 小整数值 |
SMALLINT | 2 Bytes | (-32 768,32 767) | (0,65 535) | 大整数值 |
MEDIUMINT | 3 Bytes | (-8 388 608,8 388 607) | (0,16 777 215) | 大整数值 |
INT或INTEGER | 4 Bytes | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整数值 |
BIGINT | 8 Bytes | (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) | (0,18 446 744 073 709 551 615) | 极大整数值 |
FLOAT | 4 Bytes | (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) | 0,(1.175 494 351 E-38,3.402 823 466 E+38) | 单精度 浮点数值 |
DOUBLE | 8 Bytes | (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 双精度 浮点数值 |
DECIMAL | 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2 | 依赖于M和D的值 | 依赖于M和D的值 | 小数值 |
decimal
- 非精准浮点:float,double
- 精准浮点:decimal
占用空间由定义的宽度决定,每 4 个字节可以存储 9 位数字
小数点占用一个字节
可用于存储比 bigint 更大的整型数据
字符串类型
CHAR | 0-255 bytes | 定长字符串 |
---|---|---|
VARCHAR | 0-65535 bytes | 变长字符串 |
TINYBLOB | 0-255 bytes | 不超过 255 个字符的二进制字符串 |
TINYTEXT | 0-255 bytes | 短文本字符串 |
BLOB | 0-65 535 bytes | 二进制形式的长文本数据 |
TEXT | 0-65 535 bytes | 长文本数据 |
MEDIUMBLOB | 0-16 777 215 bytes | 二进制形式的中等长度文本数据 |
MEDIUMTEXT | 0-16 777 215 bytes | 中等长度文本数据 |
LONGBLOB | 0-4 294 967 295 bytes | 二进制形式的极大文本数据 |
LONGTEXT | 0-4 294 967 295 bytes | 极大文本数据 |
日期
DATE | 3 | 1000-01-01/9999-12-31 | YYYY-MM-DD | 日期值 |
---|---|---|---|---|
TIME | 3 | ‘-838:59:59’/‘838:59:59’ | HH:MM:SS | 时间值或持续时间 |
YEAR | 1 | 1901/2155 | YYYY | 年份值 |
DATETIME | 8 | ‘1000-01-01 00:00:00’ 到 ‘9999-12-31 23:59:59’ | YYYY-MM-DD hh:mm:ss | 混合日期和时间值 |
TIMESTAMP | 4 | ‘1970-01-01 00:00:01’ UTC 到 ‘2038-01-19 03:14:07’ UTC结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 | YYYY-MM-DD hh:mm:ss | 混合日期和时间值,时间戳 |
TIMESTAMP、DATETIME
使用 TIMESTAMP(4 个字节) 或 DATETIME 类型 (8 个字节) 存储时间
TIMESTAMP 存储的时间范围 1970-01-01 00:00:01 ~ 2038-01-19-03:14:07
使用字符串
- 缺点 1:无法用日期函数进行计算和比较
- 缺点 2:用字符串存储日期要占用更多的空间
SQL
展示警告
show warnings;
基本CRUD
select *
from table1
[where Clause]
[limit N][ OFFSET M];
update table1
set name = ''
[where ];
insert into table1(name, age)
values('ming', 12);
delete from table1
连接
(left join) left outer join 即使右边为空,也保留左边的
inner join 只保留on xxx一样的交集
连接更新
https://blog.csdn.net/u012604745/article/details/80642015
UPDATE student s , class c
SET s.class_name='test00',c.stu_name='test00'
WHERE s.class_id = c.id
UPDATE student s
JOIN class c ON s.class_id = c.id
SET
s.class_name='test11',
c.stu_name='test11'
UPDATE student s
LEFT JOIN class c ON s.class_id = c.id
SET
s.class_name='test22',
c.stu_name='test22'
多数据库
oracle中不允许联表更新,需要使用游标,https://www.jianshu.com/p/61717c19c213或者update set xxx = (select xxx )
mysql中可以用left join where
postgresql可以用from where
<update id="" parameterType="java.lang.String" databaseId="oracle">
BEGIN
FOR C_CURSOR IN (
SELECT A.ROWID RID, B.VC_FUND_ACCO
FROM ${tableName} A, B
WHERE B.VC_TENANT_ID = #{tenantId,jdbcType=VARCHAR}
AND B.VC_DS_FUND_ACCO = A.VC_FUND_ACCO
AND A.VC_TENANT_ID = #{tenantId,jdbcType=VARCHAR}
)
LOOP
UPDATE ${tableName} T
SET T.VC_FUND_ACCO = C_CURSOR.VC_FUND_ACCO
WHERE T.ROWID = C_CURSOR.RID;
END LOOP;
END;
</update>
UPDATE ${tableName} A
SET A.VC_FUND_ACCO = (SELECT B.VC_FUND_ACCO
FROM B
WHERE B.VC_TENANT_ID = #{tenantId,jdbcType=VARCHAR}
AND B.VC_DS_FUND_ACCO = A.VC_FUND_ACCO
AND A.VC_TENANT_ID = #{tenantId,jdbcType=VARCHAR}
<update id="" parameterType="java.lang.String" databaseId="mysql">
UPDATE ${tableName} T, A
SET T.VC_FUND_ACCO = A.VC_FUND_ACCO
WHERE T.VC_TENANT_ID = A.VC_TENANT_ID
AND T.VC_FUND_ACCO = A.VC_DS_FUND_ACCO
AND T.VC_TENANT_ID = #{tenantId,jdbcType=VARCHAR}
</update>
<update id="" parameterType="java.lang.String" databaseId="postgresql">
UPDATE ${tableName} T
SET T.VC_FUND_ACCO = A.VC_FUND_ACCO
FROM A
WHERE T.VC_TENANT_ID = A.VC_TENANT_ID
AND T.VC_FUND_ACCO = A.VC_DS_FUND_ACCO
AND T.VC_TENANT_ID = #{tenantId,jdbcType=VARCHAR}
</update>
判断且插入
insert into TSYSPARAMETER ()
select 'UPS'
from dual where not exists (
select *
from TSYSPARAMETER
where C_CLASS='UPS'
and C_ITEM='BANK_SALE_PAY_FILE_PATH'
);
结构设置
CREATE DATABASE IF NOT EXISTS my_db default charset utf8 COLLATE utf8_general_ci;
DROP DATABASE 库名;
DROP TABLE 表名;
DELETE FROM 表名;
# 建表实例
create table teacher
(
id int(3) auto_increment not null primary key,
name char(10) not null,
address varchar(50) default '深圳',
year date
);
# 导入数据库
use tableName;
source D:\library.sql
mysql -uroot -p123456 < runoob.sql
# 导出数据库
mysqldump -uroot -p --default-character-set=latin1 --set-charset=gbk --skip-opt database_name > outfile_name.sql
用户管理
https://blog.csdn.net/u014453898/article/details/55064312
1.查看用户
use mysql;
select * from user;
2.创建用户
CREATE USER 'user_name'@'host' IDENTIFIED BY 'password';
/*创建并授权*/
GRANT ALL PRIVILEGES ON *.* TO 'mingyue'@'%'IDENTIFIED BY 'mypassword' WITH GRANT OPTION;
flush privileges;
host:本机登陆‘localhost’ ,远程登陆‘%’
# 只允许本机登陆
CREATE USER 'aaa'@'localhost' IDENTIFED BY '123456';
# 远程登录
CREATE USER 'bbb'@'%' IDENTIFED BY '123456';
# 创建新用户
CREATE USER 'aaa'@'%';
# 查看用户列表
select * from user;
# 如果添加用户无效
delete from user where user='';
flush privileges;
use mysql
update user set host ='%'where user ='root' and host ='localhost';
flush privileges;
# 修改密码
SET PASSWORD FOR root@'%'=PASSWORD('123qwe'); #root
可以看出 有 aaa用户了。但是可以看到 aaa 的权限很多都是 N,表示没有权限,因为还要为用户授予权限。
3.授权用户
GRANT privileges ON databasename.tablename TO 'user_name'@'host'
# 创建授权
GRANT ALL PRIVILEGES ON *.* TO 'mingyue'@'%' IDENTIFIED BY 'mypassword' WITH GRANT OPTION;
GRANT select, insert ON database.table TO 'aaa'@ '%';
privileges:表示要授予什么权力,
- select , insert ,delete,update等
- 如果要授予全部权力,则填 ALL
databasename.tablename
- 表示用户的权限能用在哪个库的哪个表中
- 能操作所有的数据库所有的表,则填 *
4.删除用户
DROP USER 'user_name'@'localhost' ;
# 表示删除用户mingyue
DROP USER 'mingyue'@'%';
5.设置与更改用户密码
SET PASSWORD FOR 'username'@'host' = PASSWORD('newpassword');
# 如果是设置当前用户的密码:
SET PASSWORD = PASSWORD('newpassword');
SET PASSWORD = PASSWORD(‘123456’);
6.撤销用户权限:
REVOKE privileges ON database.tablename FROM 'username'@'host';
REVOKE SELECT ON *.* FROM 'zje'@ '%'
撤销权利范围需要注意,要和原权利一致
数据库无法远程
# 添加用户权限后
delete from user where user=''; # 否则用户可能无法登录
flush privileges;
vim /etc/mysql/my.cnf
# 添加
skip-name-resolve
skip-external-locking # 如果无效,也能添加
# 注释掉,否则无法远程连接
skip-networking
# 指定IP能够访问数据库
bind-address=192.168.1.100
bind-address=0.0.0.0 # 或者直接注释
错误信息
show warnings;
函数
日期
最近日期
date(now()) DATE_ADD()
-- 今天的
select count(*)
from goods
where release_time >= date( now() )
and release_time<DATE_ADD(date(now()), INTERVAL 1 DAY);
SELECT * FROM borrow bb WHERE DATE_FORMAT(bb.create_time, '%Y%m%d') = DATE_FORMAT(CURRENT_DATE(), '%Y%m%d' );
SELECT * FROM borrow bb WHERE TO_DAYS(bb.create_time) = TO_DAYS(now());
-- 昨天
SELECT * FROM borrow bb WHERE TO_DAYS( NOW( ) ) - TO_DAYS( bb.create_time) =1;
-- 近7天
SELECT * FROM borrow bb WHERE TO_DAYS( NOW( ) ) - TO_DAYS( bb.create_time) <= 7;
SELECT bb.borrow_no,bb.create_time FROM borrow bb where DATE_SUB(CURDATE(), INTERVAL 7 DAY) <= date(bb.create_time);
-- 走索引的
and create_time >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
-- 本月
SELECT * FROM borrow bb WHERE DATE_FORMAT( bb.create_time, '%Y%m' ) = DATE_FORMAT( CURDATE( ) , '%Y%m' );
-- 上个月
SELECT * FROM borrow bb WHERE PERIOD_DIFF( date_format( now( ) , '%Y%m' ) , date_format( bb.create_time, '%Y%m' ) ) =1
时间戳
-- 返回当前时间的时间戳
select unix_timestamp();
-- from_unixtime(tt,‘yyyy-MM-dd’) 可以加上时间格式
select from_unixtime(1543943400);
时间
-- 2018-09-11 17:53:06
select NOW();
-- 2018-09-11
select CURRENT_DATE()
分组
group_concat(score)
SELECT id, GROUP_CONCAT( DISTINCT score SEPARATOR '; ' ORDER BY score asc )
FROM testgroup GROUP BY id
id score
1 99;100;123
排序
--- 查询到的数据排序,加序号
select row_number() over(
order by socre desc
) `rank`
, *
from student
--- 分数一样的,相同排名,但是跳跃排序
select rank() over(
order by score desc
) `rank`
, *
from studnet
---分 数一样的,相同排名,顺序排序
select dense_rank() over(
order by score desc
) `rank`
, *
from student
字符串函数
函数名 | 解释 | |
---|---|---|
lower(column|str) | 全转小写 | |
upper(column|str) | 大写 | |
concat(column|str,column|str) | 连接 | |
substr(str, pos [,len]) | 从pos取len长度(默认到尾),pos是位置 | |
instr(str, substr) | 从str找substr第一次出现的位置,大于0为包含(其返回是位置 不是下标) | |
trim(str),ltrim(str), rtrim(str) | 去除空格 | |
lpad(str, n, pad) | 用字符串pad对str最左边进行填充, 直到长度为n个字符长度 | |
replace(str, a, b) | 将字符串str中的a更换为b | |
strcmp(s1, s2) | 比较字符串s1, s2。0一样,小于为-1 |
并发
锁
for update
悲观锁(适合写多),在用户A获取获取 id=1 的商品信息时对该行记录加锁,期间其他用户阻塞等待访问该记录
乐观锁(适合读多),每次获取商品时,不对该商品加锁。在更新数据的时候需要比较程序中的库存量与数据库中的库存量是否相等,如果相等则进行更新,反之程序重新获取库存量,再次进行比较,直到两个库存量的数值相等才进行数据更新
innoDb默认是行级别锁,能使用到索引,是行级锁,否则是表级别
for update仅仅使用innodb必须开启事务,在begin、commit之间生效
获取到互斥锁后,只有事务提交或失败后才会释放
避免回滚情况如读未提交:A事务获取了T1的锁,进行修改未提交,B事务也获取了T1的值,也进行修改,如果A事务完成提。交,就没问题,但是如果A事务回滚,B获取的就是脏数据。
其他
序列号
创建
-- 20221227 yixh14641 T202212203994-1 大额限制 新增序号oralce
DECLARE
ICOUNT INTEGER := 0;
BEGIN
SELECT COUNT(1) INTO ICOUNT FROM USER_SEQUENCES T
WHERE T.SEQUENCE_NAME = UPPER('QLRLIMIT');
IF ICOUNT = 0 THEN
EXECUTE IMMEDIATE 'create sequence QLRLIMIT
minvalue 1
maxvalue 999999999
start with 1
increment by 1
nocache';
END IF;
END;
/
-- 20221227 yixh14641 T202212203994-1 大额限制 新增序列mysql
delimiter //
drop procedure if exists my_test_proc;
create procedure my_test_proc()
begin
declare v_rowcount numeric(5);
select count(*) into v_rowcount from dual
where exists (select 1 from tc_tsequence where NAME = 'QLRLIMIT');
if v_rowcount = 0 then
insert into tc_tsequence (VC_TENANT_ID, VC_SERIAL_TYPE, NAME, CURRENT_VALUE, INCREMENTS)
values ('10000', 'DB_REDIS_RANGE', 'QLRLIMIT', 1, 1);
end if;
end;
call my_test_proc();
//
-- 20221227 yixh14641 T202212203994-1 大额限制 新增序号
if (SELECT COUNT(1) FROM information_schema.sequences WHERE upper(sequence_name) = 'QLRLIMIT') = 0
then
CREATE SEQUENCE QLRLIMIT INCREMENT 1 MINVALUE 1 MAXVALUE 9999999999 START 1 CACHE 1;
end if;
DECLARE
V_ROWCOUNT INTEGER;
BEGIN
SELECT COUNT(1)
INTO V_ROWCOUNT
FROM USER_SEQUENCES
WHERE SEQUENCE_NAME = 'QUPLOADFILEID';
IF V_ROWCOUNT = 1 THEN
EXECUTE IMMEDIATE 'DROP SEQUENCE QUPLOADFILEID';
END IF;
END;
/
DECLARE
FILE_ID NUMBER ;
BEGIN
SELECT NVL(MAX(L_ID),0)+1 INTO FILE_ID FROM TC_TUPLOADFILE;
EXECUTE IMMEDIATE 'CREATE SEQUENCE QUPLOADFILEID MINVALUE 1 NOMAXVALUE START WITH '||FILE_ID||' INCREMENT BY 1 CACHE 20';
END;
/
序列号修改
方式一:修改
-- 修改递增量为n,达到期望的值
alter sequence seq_t_test increment by n;
-- 取一次,就能获取到x+n的了
select seq_t_test.nextval from dual;
-- 修改为1增量
alter sequence seq_t_test increment by 1;
方式二:删除再增加
drop sequence seq_t_test;
create sequence seq_t_test
increment by 1
start with 1;
序列号如何生成?如果生成了不使用,会怎样?
- oracle自带、mysql通过自建表实现
- 获取了就会递增
对比
oracle中,序列号能够自带
mysql中,需要通过表来控制
-- 更新并获取序列号
CREATE DEFINER=`root`@`%` FUNCTION `NEXT_VAL`(seq_name VARCHAR(50)) RETURNS decimal(32,0)
BEGIN
UPDATE TC_TSEQUENCE
SET current_value = current_value + increments
WHERE name = seq_name;
RETURN CURRENT_VAL(seq_name);
END
-- 获取当前序列号
CREATE DEFINER=`root`@`%` FUNCTION `CURRENT_VAL`(seq_name VARCHAR(50)) RETURNS decimal(32,0)
BEGIN
DECLARE value Integer;
SET value = 0;
SELECT current_value INTO value
FROM TC_TSEQUENCE
WHERE name = seq_name;
RETURN value;
END
-- 序列号索引表,current_value,increments
-- 唯一键 `NAME`, `VC_SERIAL_TYPE`, `VC_TENANT_ID`
程序中通过SequenceFactoryBean工厂控制获取mysql还是oracle的序列器
序列器接口的方法有添加、删除、获取下一个值
<select id="selectSerialNo" resultType="java.lang.Integer" databaseId="mysql">
SELECT CONVERT(NEXT_VAL('QPRODUCTSTATENO'), SIGNED)
</select>
<select id="selectSerialNo" resultType="java.lang.Integer" databaseId="oracle">
SELECT TO_NUMBER(QPRODUCTSTATENO.nextval) from dual
</select>
<select id="selectSerialNo" resultType="java.lang.Integer" databaseId="postgresql">
SELECT (nextval('QPRODUCTSTATENO'))
</select>
序列号脚本
序列号脚本
oracle
-- 2023/02/15 T202302144211 异步复核,产品状态预设置使用序列号 sumy45276
DECLARE
V_ROWCOUNT INTEGER;
BEGIN
SELECT COUNT(1)
INTO V_ROWCOUNT
FROM USER_SEQUENCES
WHERE SEQUENCE_NAME = 'QPRODUCTSTATENO';
IF V_ROWCOUNT = 1 THEN
EXECUTE IMMEDIATE 'DROP SEQUENCE QPRODUCTSTATENO';
END IF;
END;
/
DECLARE
PRODUCT_STATE_NO NUMBER ;
BEGIN
SELECT NVL(MAX(L_PRODUCT_STATE_NO),0)+1 INTO PRODUCT_STATE_NO FROM TC_TPRODUCTSTATESCHEDULE;
EXECUTE IMMEDIATE 'CREATE SEQUENCE QPRODUCTSTATENO MINVALUE 1 NOMAXVALUE START WITH '||PRODUCT_STATE_NO||' INCREMENT BY 1 CACHE 20';
END;
/
mysql
-- 2023/02/15 T202302144211 异步复核,产品状态预设置使用序列号 sumy45276
delimiter //
drop procedure if exists my_test_proc;
create procedure my_test_proc()
begin
declare v_rowcount numeric(5);
declare v_maxno int;
select count(*) into v_rowcount from dual
where exists (select 1 from tc_tsequence where NAME = 'QPRODUCTSTATENO');
SELECT ifnull(MAX(L_PRODUCT_STATE_NO),0)+1 INTO v_maxno FROM TC_TPRODUCTSTATESCHEDULE;
if v_rowcount = 0 then
insert into tc_tsequence (VC_TENANT_ID, VC_SERIAL_TYPE, NAME, CURRENT_VALUE, INCREMENTS)
values ('10000', 'DB_REDIS_RANGE', 'QPRODUCTSTATENO', v_maxno, 1);
end if;
end;
call my_test_proc();
//
postgresql
-- 2023/02/15 T202302144211 异步复核,产品状态预设置使用序列号 sumy45276
do
$$
declare v_rowcount int default 0;
declare v_maxno int default 0;
declare sqltxt text;
begin
SELECT COUNT(1) INTO v_rowcount FROM information_schema.sequences WHERE upper(sequence_name) = 'QPRODUCTSTATENO';
SELECT coalesce(MAX(L_PRODUCT_STATE_NO),0)+1 into v_maxno FROM TC_TPRODUCTSTATESCHEDULE;
if v_rowcount = 0 then
sqltxt := concat(concat('CREATE SEQUENCE QPRODUCTSTATENO
INCREMENT 1
MINVALUE 1
MAXVALUE 9999999999
START ', v_maxno), ' CACHE 20;');
execute sqltxt;
end if;
end;
$$;
nocache
https://www.cnblogs.com/friday69/p/9999332.html
序列是一数据库对象,利用它可生成唯一的整数。一个序列的值是由特别的Oracle程序自动生成。
如果不设定cycle循环的话,每一个序列号是唯一的。 当一个序列号生成时,序列是递增
当使用到序列的事务发生回滚。会造成序列号不连续
cache的作用:当大量语句发生请求,申请序列时,为了避免序列在运用层实现序列而引起的性能瓶颈。Oracle序列允许将序列提前生成 cache x个先存入内存,
在发生大量申请序列语句时,可直接到运行最快的内存中去得到序列。但cache个数也不能设置太大,因为在数据库重启时,会清空内存信息,预存在内存中的序列会丢失,
当数据库再次启动后,序列从上次内存中最大的序列号+1 开始存入cache x个。
比如你的sequence中cache 100,那当你sequence取到90时突然断电,那么在你重启数据库后,sequence的值将从101开始。
NOCACHE
- 创建nocache sequence在高并发访问时,容易导致row cache lock等待事件,主要原因是每次获取nextval时都需要修改rowcache中的字典信息
- 由于每次修改字典信息都需要commit,可能导致log file sync等待,nocache sequence在RAC环境下,会对基于sequence生成的列创建的索引造成实例间大量索引块争用
基于以上问题,避免创建nocache sequence。
忘记密码
https://developer.aliyun.com/article/792438
忽略表大小写
/etc/my.cnf
[mysqld]
lower_case_table_names=1
重启
Row size too large (> 8126)
[mysqld]
innodb_strict_mode = 0
max_allowed_packet = 1G
innodb_log_file_size = 512M
innodb_log_buffer_size = 512M
健康状态
连接数
# 更为全面的进程信息
SHOW full processlist;
# 查看当前失败连接数
SHOW GLOBAL STATUS LIKE 'aborted_connects'
# 由于客户没有正确关闭连接而死掉的连接数
SHOW GLOBAL STATUS LIKE 'aborted_clients'
# 最大连接数
show variables like '%max_connections%';
# 线程数需要在一个合理的范围之内
show global status like 'Thread%';
# 如果我们在MySQL服务器配置文件中设置了thread_cache_size,当客户端断开之后,服务器处理此客户的线程将会缓存起来以响应下一个客户而不是销毁(前提是缓存数未达上限)。
修改
show variables like '%max_connections%';
set global max_connections=1000
# /etc/my.cnf
[mysqld]
max_connections = 1000
thread_cache_size = 64
# 忽略表大小写
lower_case_table_names=1
连接控制
show variables like '%timeout%';
connect_timeout 10
delayed_insert_timeout 300
have_statement_timeout YES
innodb_flush_log_at_timeout 1
innodb_lock_wait_timeout 50
innodb_rollback_on_timeout OFF
interactive_timeout 28800
lock_wait_timeout 31536000
net_read_timeout 30
net_write_timeout 60
rpl_stop_slave_timeout 31536000
slave_net_timeout 60
wait_timeout 28800
- connect_timeout:默认为10S,在获取连接阶段(authenticate)起作用
- wait_timeout:默认是8小时,即28800秒,在连接空闲阶段(sleep)起作用
- interactive_timeout:默认是8小时,即28800秒,在连接空闲阶段(sleep)起作用
- net_read_timeout:默认是30S
- net_write_timeout:默认是60S
死锁
SHOW ENGINE INNODB STATUS
存储过程
结构
CREATE
[DEFINER = { user | CURRENT_USER }]
PROCEDURE sp_name ([proc_parameter[,...]])
[characteristic ...] routine_body
proc_parameter:
[ IN | OUT | INOUT ] param_name type
characteristic:
COMMENT 'string'
| LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
routine_body:
Valid SQL routine statement
[begin_label:] BEGIN
[statement_list]
……
END [end_label]
-- 结束符号
DELIMITER $$
或
DELIMITER //
-- 声明
CREATE PROCEDURE demo_in_parameter(IN p_in int)
-- 定义变量
DECLARE l_int int unsigned default 4000000;
-- 赋值
SET @p_in=1
参数
输入
mysql> delimiter $$
mysql> create procedure in_param(in p_in int)
-> begin
-> select p_in;
-> set p_in=2;
-> select P_in;
-> end$$
mysql> delimiter ;
# 全局变量
mysql> set @p_in=1;
mysql> call in_param(@p_in);
输出
out不接受参数,传进来的值会被存储过程改变
mysql> delimiter //
mysql> create procedure out_param(out p_out int)
-> begin
-> select p_out; # 首先是null,因为是out,不接受值
-> set p_out=2;
-> select p_out; # 改为了2,能够输出
-> end
-> //
mysql> delimiter ;
mysql> set @p_out=1;
mysql> call out_param(@p_out);
mysql> select @p_out; # 存储过程内改为了2
inout
能够接受、也能改变
mysql> delimiter $$
mysql> create procedure inout_param(inout p_inout int)
-> begin
-> select p_inout;
-> set p_inout=2;
-> select p_inout;
-> end
-> $$
mysql> delimiter ;
mysql> set @p_inout=1;
mysql> call inout_param(@p_inout);
+---------+
| p_inout |
+---------+
| 1 |
+---------+
+---------+
| p_inout |
+---------+
| 2 |
+---------+
mysql> select @p_inout;
+----------+
| @p_inout |
+----------+
| 2 |
+----------+
#调用了inout_param存储过程,接受了输入的参数,也输出参数,改变了变量
变量
定义
DECLAREvariable_name [,variable_name...] datatype [DEFAULT value];
-- datatype 为 MySQL 的数据类型,如: int, float, date,varchar(length)
DECLARE l_int int unsigned default 4000000;
DECLARE l_numeric number(8,2) DEFAULT 9.95;
DECLARE l_date date DEFAULT '1999-12-31';
DECLARE l_datetime datetime DEFAULT '1999-12-31 23:59:59';
DECLARE l_varchar varchar(255) DEFAULT 'This will not be padded';
赋值
SET 变量名 = 表达式值 [,variable_name = expression ...]
用户变量
mysql > SELECT 'Hello World' into @x;
mysql > SELECT @x;
| Hello World |
# 使用用户变量
mysql > CREATE PROCEDURE GreetWorld( ) SELECT CONCAT(@greeting,' World');
mysql > SET @greeting='Hello';
mysql > CALL GreetWorld( );
+----------------------------+
| CONCAT(@greeting,' World') |
+----------------------------+
| Hello World |
+----------------------------+
控制语句
if then, else
mysql > DELIMITER //
mysql > CREATE PROCEDURE proc2(IN parameter int)
-> begin
-> declare var int;
-> set var=parameter+1;
-> if var=0 then
-> insert into t values(17);
-> end if;
-> if parameter=0 then
-> update t set s1=s1+1;
-> else
-> update t set s1=s1+2;
-> end if;
-> end;
-> //
mysql > DELIMITER ;
case
case
when var=0 then
insert into t values(30);
when var>0 then
when var<0 then
else
end case
循环
while
while 条件 do
--循环体
endwhile
repeat···· end repeat
像do while
repeat
--循环体
until 循环条件 v>=5
end repeat;
loop ·····endloop
一直循环,通过if leave LOOP_LABLE结束
mysql > DELIMITER //
mysql > CREATE PROCEDURE proc6 ()
-> begin
-> declare v int;
-> set v=0;
-> LOOP_LABLE:loop
-> insert into t values(v);
-> set v=v+1;
-> if v >=5 then
-> leave LOOP_LABLE;
-> end if;
-> end loop;
-> end;
-> //
mysql > DELIMITER ;
ITERATE
像goto
mysql > DELIMITER //
mysql > CREATE PROCEDURE proc10 ()
-> begin
-> declare v int;
-> set v=0;
-> LOOP_LABLE:loop
-> if v=3 then
-> set v=v+1;
-> ITERATE LOOP_LABLE;
-> end if;
-> insert into t values(v);
-> set v=v+1;
-> if v>=5 then
-> leave LOOP_LABLE;
-> end if;
-> end loop;
-> end;
-> //
mysql > DELIMITER ;
样例
-- 改为使用 // 否则可能报错
delimiter $$ -- 将语句的结束符号从分号;临时改为两个$$(可以是自定义),使得过程体中使用的分号被直接传递到服务器,而不会被客户端(如mysql)解释
CREATE PROCEDURE delete_matches(IN p_playerno INTEGER)
BEGIN
DELETE FROM MATCHES
WHERE playerno = p_playerno;
END$$
delimiter; -- 将语句的结束符号恢复为分号
-- 使用
call sp_name[(传参)];
游标
from:http://c.biancheng.net/view/7823.html
声明
DECLARE cursor_name CURSOR FOR select_statement;
mysql> DELIMITER //
mysql> CREATE PROCEDURE processnames()
-> BEGIN
-> DECLARE nameCursor CURSOR
-> FOR
-> SELECT name FROM tb_student;
-> END//
使用
-- 打开才能提取数据
OPEN cursor_name;
-- 使用
FETCH cursor_name INTO var_name [,var_name]...;
-- 关闭
CLOSE cursor_name;
样例1
mysql> DELIMITER //
mysql> CREATE PROCEDURE test_cursor (in param INT(10),out result VARCHAR(90))
-> BEGIN
-> DECLARE name VARCHAR(20);
-> DECLARE pass VARCHAR(20);
-> DECLARE done INT;
-> DECLARE cur_test CURSOR FOR SELECT user_name,user_pass FROM users;
-> DECLARE continue handler FOR SQLSTATE '02000' SET done = 1; -- 定义cursor未找到(NOT FOUND或SQLSTATE '02000')的条件来标识游标结束
-> IF param THEN INTO result FROM users WHERE id = param;
-> ELSE
-> OPEN cur_test;
-> repeat
-> FETCH cur_test into name,pass;
-> SELECT concat_ws(',',result,name,pass) INTO result;
-> until done
-> END repeat;
-> CLOSE cur_test;
-> END IF;
-> END //
mysql> call test_cursor(3,@test)//
样例2
mysql> CREATE PROCEDURE pro_users()
-> BEGIN
-> DECLARE result VARCHAR(100);
-> DECLARE no INT;
-> DECLARE cur_1 CURSOR FOR SELECT user_name FROM users;
-> DECLARE CONTINUE HANDLER FOR NOT FOUND SET no=1; -- 当找不到数据时,设置 no = 1
-> SET no=0;
-> OPEN cur_1;
-> WHILE no=0 do
-> FETCH cur_1 into result;
-> UPDATE users SET user_name='MySQL'
-> WHERE user_name=result;
-> END WHILE;
-> CLOSE cur_1;
-> END //
预处理
某需求某一条 SQL 语句可能会被反复调用执行,或者每次执行的时候只有个别的值不同
一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止 SQL 注入。
MySQL 官方将 prepare、execute、deallocate 统称为 PREPARE STATEMENT
# 定义预处理语句
PREPARE stmt_name FROM preparable_stmt;
# 执行预处理语句
EXECUTE stmt_name [USING @var_name [, @var_name] ...];
# 删除(释放)定义
{DEALLOCATE | DROP} PREPARE stmt_name;
字符串定义
mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> SET @a = 3;
mysql> SET @b = 4;
mysql> EXECUTE stmt1 USING @a, @b;
mysql> DEALLOCATE PREPARE stmt1;
变量定义
mysql> SET @s = 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> PREPARE stmt2 FROM @s;
mysql> SET @c = 6;
mysql> SET @d = 8;
mysql> EXECUTE stmt2 USING @c, @d;
mysql> DEALLOCATE PREPARE stmt2;
limit
对于 LIMIT 子句中的值,必须是常量,不得使用变量,用 PREPARE 语句
# mysql> SET @skip = 100; SET @numrows = 3;
# mysql> SELECT * FROM t1 LIMIT @skip, @numrows;
# ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@skip, @numrows' at line 1
mysql> PREPARE stmt3 FROM "SELECT * FROM t1 LIMIT ?, ?";
mysql> EXECUTE stmt3 USING @skip, @numrows;
mysql> DEALLOCATE PREPARE stmt3;
注意:
定义一个已存在的 stmt_name ,原有的将被立即释放,类似于变量的重新赋值
PREPARE stmt_name 的作用域是session级
information_schema
information_schema数据库表说明:
SCHEMATA表:提供了当前mysql实例中所有数据库的信息。是show databases的结果取之此表。
TABLES表:提供了关于数据库中的表的信息(包括视图)。详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。是show tables from schemaname的结果取之此表。
COLUMNS表:提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。是show columns from schemaname.tablename的结果取之此表。
STATISTICS表:提供了关于表索引的信息。是show index from schemaname.tablename的结果取之此表。
USER_PRIVILEGES(用户权限)表:给出了关于全程权限的信息。该信息源自mysql.user授权表。是非标准表。
SCHEMA_PRIVILEGES(方案权限)表:给出了关于方案(数据库)权限的信息。该信息来自mysql.db授权表。是非标准表。
TABLE_PRIVILEGES(表权限)表:给出了关于表权限的信息。该信息源自mysql.tables_priv授权表。是非标准表。
COLUMN_PRIVILEGES(列权限)表:给出了关于列权限的信息。该信息源自mysql.columns_priv授权表。是非标准表。
CHARACTER_SETS(字符集)表:提供了mysql实例可用字符集的信息。是SHOW CHARACTER SET结果集取之此表。
COLLATIONS表:提供了关于各字符集的对照信息。
COLLATION_CHARACTER_SET_APPLICABILITY表:指明了可用于校对的字符集。这些列等效于SHOW COLLATION的前两个显示字段。
TABLE_CONSTRAINTS表:描述了存在约束的表。以及表的约束类型。
KEY_COLUMN_USAGE表:描述了具有约束的键列。
ROUTINES表:提供了关于存储子程序(存储程序和函数)的信息。此时,ROUTINES表不包含自定义函数(UDF)。名为“mysql.proc name”的列指明了对应于INFORMATION_SCHEMA.ROUTINES表的mysql.proc表列。
VIEWS表:给出了关于数据库中的视图的信息。需要有show views权限,否则无法查看视图信息。
TRIGGERS表:提供了关于触发程序的信息。必须有super权限才能查看该表。
oracle
高性能高可靠,面向对象关系型数据库管理系统
- 关系型Oracle、MySQL、SQL Server、PostgreSQL
- 非关系型:Mongodb、Redis、Hbase
- 国产:TiDB、达梦、OceanBase、LightDB
体系结构
用户进程 -> 服务器进程 ->
硬盘文件:【数据文件、控制文件、重做日志文件】、参数文件、口令文件、归档日志文件
逻辑结构和物理结构
物理结构(不要动)
数据文件:实际数据
重做日志:对数据库的修改记录,数据失败后恢复,至少要两个
控制文件:维护和校验数据库一致性信息
参数文件:oracle实例特性
口令验证:验证启动和关闭oracle实例的用户
归档日志文件:重做日志的备份,用以恢复数据
追踪文件:后台进程和服务器
逻辑结构
操作系统一个块4kb,oracle一个块8kb
基础概念
数据库对象
user/ profile /role /directory
- user: 数据库用户
- profile:每个用户有且仅有一个,数据库资源限制
schema:一组数据库逻辑数据结构的集合,一个用户创建后自动创建一个同名的schema
schema objects
table
- 数据的集合,二维表的形式存在,每一列代表一个属性,每一行为表的一个实例
index
- 索引可以提高表中数据检索的性能,通常由表的一个或多个列组成
- 注意返回的数据量,如果大量的数据,遍历表可能还快
constraint
- 约束,对数据库表中的值(列)指定规则,确保其完整性,not null / unique /pk / foreign key / check
view
- 视图本质是一段查询,逻辑上代表一张或多张表组织起来的数据,可对外展示数据的裁剪和权限的管控
synonym
- 同义词,table view取别名
sequence
- 生成为数据库提供自动生成的唯一值
database link
- 允许授权的用户通过
connect
sqlplus /as sysdba
连接上空闲实例
启动 startup
startup
nomount:验证命令文件,读取参数文件,记录警告日志文件,分配内存和启动进程
mount:打开控制文件,验证正确性,获取数据文件和重做日志文件的状态
open: 打开数据文件和重做日志文件
shutdown
immediate:没有结束的事务自动rollback
# ORACLE启动
cd /u01/app/oracle
su - oracle
# 进入Sqlplus控制台
sqlplus /nolog
# sql
start
# 以系统管理员身份登录
connect /as sysdba
exit
# 进入监听器控制台
lsnrctl
start
exit
su - root
sqlplus
# server_name
jdbc:oracle:thin:@//<host>:<port>/<service_name>
# sid
jdbc:oracle:thin:@<host>:<port>:<SID>
sqlplus 用户名/密码@数据库主机Ip/service
安装:https://blog.csdn.net/wherejaly/article/details/50857255
http://www.oracle.com/technetwork/topics/winx64soft-089540.html
instantclient-basic-windows.x64-12.1.0.2.0.zip
instantclient-sqlplus-windows.x64-12.1.0.2.0.zip
解压后文件名应该为instantclient_12_1,在运行工具之前我们需要在windows中配置以下环境变量,先右键计算机->属性->高级系统设置->环境变量,在系统变量中找到Path并在后面加上刚才解压后instantclient_12_1的目录与sdk子目录
C:\Program Files\instantclient_12_1\;C:\Program Files\instantclient_12_1\sdk;
再新增两个变量到系统环境中
TNS_ADMIN=C:\Program Files\instantclient_11_2
NLS_LANG=AMERICAN_AMERICA.UTF8
配置文件:$oracle_home/network/admin/listener.ora,监听端口1521
监听器的作用:
- 监听客户端请求
- 分配oracle server process
-
rac
oracle real application clusters
RAC,实时应用集群
- 通过心跳网络内联为逻辑上的单数据库对外提供服务
SQL
DQL / *DML / DDL */ DCL
DML:数据操作语言
- select
- insert
- update
- delete
- merge
- explain plan
- lock table
DDL:数据定义语言
- create / alter / drop database
- truncate
- grant revoke
- audit noaudit
- comment
TCL 事务控制语言
- commit
- rollback rollback to savepoint
- savepoint
- set transaction
- set constraint
other 会话控制+系统控制
CRUD
select column
from table
[where ]
[group by ]
[having ]
[order by column]
update table
set column = value, []
[where ]
insert into table[(column[, column])]
values(value[, value]);
delete from table
[where condition]
--- 真正释放删除的数据空间
truncate table table_name;
分页
通过rownum将行号传递给上一层,让上一层处理分页
-- oracle
select *
from (
select rownum rn, t.*
from t
where rownum <= #{end}
)
where rn >= (#{start} +1)
-- mysql
select *
from t
limit #{start}, #{pageSize}
-- oracle 设计
select *
from (
select t1.COLUMN_NAME,
t1.DATA_TYPE,
t1.DATA_LENGTH,
rownum rn
from(
select t.COLUMN_NAME, t.DATA_TYPE, t.DATA_LENGTH, t.DATA_SCALE
from (
select *
from user_tab_cols
where DATA_TYPE != 'VARCHAR2'
) t
group by t.COLUMN_NAME, t.DATA_TYPE, t.DATA_LENGTH, t.DATA_SCALE
) t1
) t2
where t2.rn < 10;
优化
优化器: SQL分析和执行的优化工具,负责制定SQL的执行计划,是SQL执行的核心
种类:
- RBO(role base optimizer)基于规则
- CBO(Cost base optimizer)基于成本,或者统计信息
执行计划:
- 根据统计信息进行执行
--- select * from table(dbms_xplan.display_curor('')) 获取
统计信息:
hint:
- 强制走索引或者全表扫描
索引:
表的连接方式:
- 嵌套循环
- hash join (大表关联),基于CBO
- merge join,适合不等价连接
常用流程
su – oracle #不是必需,适合于没有DBA密码时使用,可以不用密码来进入sqlplus界面。
sqlplus /nolog 或sqlplus system/manager 或./sqlplus ;
connect / as sysdba ;(as sysoper)或
connect internal/oracle AS SYSDBA ;(scott/tiger)
conn sys/change_on_install as sysdba;
# 启动数据库实例
startup;
# 所有数据库: select * from v$database;
select name from v$database;
desc v$databases; 查看数据库结构字段
# 查看哪些用户拥有SYSDBA、SYSOPER权限:
SQL>select * from V_$PWFILE_USERS;
# 查看当前数据库连接用户
show user;
# 进入test数据库
database test;
# 数据库实例
select * from v$instance;
# 当前库的所有数据表:
select TABLE_NAME from all_tables;
select * from all_tables;
elect table_name from all_tables where table_name like ‘u’;
# 查看表结构:
desc all_tables;
# CQI.T_BBS_XUSER的所有字段结构:
desc CQI.T_BBS_XUSER;
# CQI.T_BBS_XUSER表中的记录:
select * from CQI.T_BBS_XUSER;
# 增加数据库用户:(test11/test)
create user test11 identified by test default tablespace users Temporary TABLESPACE Temp;
# 用户授权:
grant connect,resource,dba to test11;
grant sysdba to test11;
commit;
# 更改数据库用户的密码:(将sys与system的密码改为test.)
alter user sys indentified by test;
alter user system indentified by test;
查看主键
select cu.* from user_cons_columns cu, user_constraints au where cu.constraint_name = au.constraint_name and au.constraint_type = 'P' and au.table_name = upper('tablename')
表结构
select * from user_tab_columns where table_name='大写表名'
表索引
select *
from all_indexes
where table_name = '表名'
-- user_indexes
select *
from user_indexes
where table_name = '表名'
-- 索引对应哪些列
select *
from user_ind_columns
where table_name='TC_TCUSTINFO'
order by INDEX_OWNER ,INDEX_NAME,
COLUMN_POSITION
集合操作
条件:两个结果集的字段个数和字段类型一一对应
minus
第一个表的数据减去第二个表的数据,不包括重复行,进行默认排序
union all
单纯合并两个集合,不去重、不排序,包括重复行
union
合并两集合,进行去重排序
intersect
两集合交集,找出重复的,不包括重复行,进行默认规则排序
日期
select TO_CHAR(SYSDATE, 'YYMMDD')
from dual;
数据类型
https://www.cnblogs.com/abeam/p/12153432.html
数值类型
number(p,s)
即可以用于存储整数,也可以存储小数
p表示有效位,从左边第一个非0的数字开始数,到结尾的长度,取值范围:1 ~ 38;
s表示小数位,取值范围:-84 ~ 127。
类型 | 描述 | 存储描述 |
---|---|---|
DECIMAL(P,S) | 数字类型 | P为有效位,S为小数 |
INTEGER | 整数类型 | 小的整数 |
FLOAT | 浮点数类型 | NUMBER(38), 双精度 |
REAL | 实数类型 | NUMBER(63), 精度更高 |
属于 number 类型的“变种”,而且使用 number 类型都能替代这些数据类型,所以这里不过多去研究它们
字符类型
四种字符类型比较:
类型 | 可变长度 | 一个空间占用字节数 | 最大字节数(bytes) | 适用场景 |
---|---|---|---|---|
CHAR | 否 | 1 | 2000、 char(2000) | 定长:英文、数字 |
NCHAR | 否 | 2 | 2000, nchar(1000) | 定长:中文 |
VARCHAR2 | 是 | 1 | 4000, varchar2(40000) | 变长:英文、数字、中文 |
NCARCHAR2 | 是 | 2 | 4000, ncarchar2(2000) | 变长:中文 |
对于中文,在这四种类型中存储,都是占2个或2个以上字节;
- 在 ORACLE 数据库汉字占用几个字节,是根据 ORACLE 中字符集编码决定,一般情况,数据库的 NLS_CHARACTERSET 为 AL32UTF8 或 UTF8,一个汉字占三到四个字节;如果 NLS_CHARACTERSET 为 ZHS16GBK,则一个字符占两个字节。
对于英文或数字,在 CHAR 和 VARCHAR2 中占一个字节,在 NCHAR 和 NVARCHAR2 中占两个字节。
CHAR
用于存储固定长度的字符串,一个空间占用1个字节,最多存储2000个字节,即:char(2000),这里的2000表示字节数。通常也就是1000个汉字
NCHAR
根据字符集而定的固定长度字符串。用于存储固定长度的字符串,一个空间占用2个字节,最多存储2000个字节,即:nchar(1000),注意这里的1000表示字符数
VARCHAR2
VARCHAR2 与 CHAR 类似,不同的是 VARCHAR2 用于存储可变长度的字符串。最大长度是 CHAR 的两倍,也就是4000个字节,即:varchar2(4000) ,通常也就是2000个汉字,或者4000个字母、数字等
NVARCHAR2
根据字符集而定的可变长度字符串。NVARCHAR2 与 NCHAR 类似,不同的是 NVARCHAR2 用于存储可变长度的字符串。最大长度是 NCHAR 的两倍,也就是4000个字节,即:nvarchar2(2000) ,通常也就是2000个汉字、字母、数字等。
与 NCHAR 一样,一个英文或数字都占用了两个字节,但是长度是不固定的
-- name = '中文' 'test'
select name, dump(name) from t_nvarchar2;
日期类型
date
date 用于存储日期和时间类型,date 类型的默认格式为:DD-MM-YYYY
timestamp
时间戳类型,与 DATE 相比较,TIMESTAMP 类型具有小数位毫秒数,比 DATE 的精度更高。
大数据与二进制类型
long
用于存储可变长度的超长字符串,最大长度为2G,通常用于存储备注字段
提示:LONG 是一种较老的数据类型,将来会逐渐被BLOB、CLOB、NCLOB等大的对象数据类型所取代。
clob
字符型大型对象,最大长度为4G
-- 使用
-- Create table
create table TEMP
(
name VARCHAR2(200),
age NUMBER,
temp_clob CLOB
);
-- 直接拼接的长度只能是varchar2
SELECT t.name, t.temp_clob FROM temp t; --普通查询 INSERT INTO temp t VALUES ('Grand.Jon', 22, '加入博客园的第一天');
--使用PL/SQL语法,采取绑定变量的方式解决,而不是直接拼接SQL
DECLARE
V_LANG CLOB := '待插入的海量字符串';
V_UPDATE CLOB := '更新的海量字符串';
BEGIN
INSERT INTO temp t VALUES ('Grand.Jon', 22, V_LANG); --增加
UPDATE temp t SET t.temp_clob = V_UPDATE WHERE rownum = 1; --修改
SELECT t.NAME, dbms_lob.substr(t.temp_clob) FROM TEMP t; --查询 将CLOB转成字符类型
DELETE temp t WHERE rownum = 1; --按列删除
COMMIT;
END;
/
dbms_lob
dbms_lob.createtemporary(V_SQL,true); --创建一个临时clob,用来存储拼接的sql
dbms_lob.write(v_SQL,'写入信息'); --写入操作
dbms_lob.append(v_SQL,','); --拼接clob
dbms_lob.substr(v_SQL); --截取clob,不传参数就是全部读取
dbms_lob.freetemporary(v_SQL); --释放clob
mybatis
直接string接收就行
<result column="temp_clob" property="content" jdbcType="Clob" typeHandler="org.apache.ibatis.type.ClobTypeHandler"/>
NCLOB
根据字符集而定的字符数据,最大长度为4G
BLOB
BLOG 是一种二进制大型对象(Binary Large Object),最大长度为4G,适用于存储非文本的字节流数据
常用类型
CREATE TABLE Temp01(ID number, Data_Type varchar2(16), Value varchar2(256), Type varchar2(256));
declare
v_integer integer := 22;
v_decimal decimal(5,2) := 22.6;
v_float float := 22.7;
v_real real := 22.8;
v_number number(5,2) := 22.9;
v_char char(1) := 'z';
v_nchar nchar(1) := '中';
v_varchar2 varchar2(2) := 'z';
v_nvarchar2 nvarchar2(2) := '中';
v_varchar varchar(1) := 'z';
v_date date := to_date('2020-12-31', 'yyyy-mm-dd');
v_timestamp timestamp := to_timestamp('2020-12-31 23:59:59.999', 'yyyy-mm-dd hh24:mi:ss.ff3');
v_long long := 'aaa';
begin
INSERT INTO Temp01 SELECT * FROM (
SELECT 1, 'integer', to_char(v_integer), dump(v_integer) FROM dual UNION
SELECT 2, 'decimal(5,2)', to_char(v_decimal), dump(v_decimal) FROM dual UNION
SELECT 3, 'float', to_char(v_float), dump(v_float) FROM dual UNION
SELECT 4, 'real', to_char(v_real), dump(v_real) FROM dual UNION
SELECT 5, 'number(5,2)', to_char(v_number), dump(v_number) FROM dual UNION
SELECT 6, 'char(1)', to_char(v_char), dump(v_char) FROM dual UNION
SELECT 7, 'nchar(1)', to_char(v_nchar), dump(v_nchar) FROM dual UNION
SELECT 8, 'varchar2(2)', to_char(v_varchar2), dump(v_varchar2) FROM dual UNION
SELECT 9, 'nvarchar2(2)', to_char(v_nvarchar2), dump(v_nvarchar2) FROM dual UNION
SELECT 10, 'varchar(1)', to_char(v_varchar), dump(v_varchar) FROM dual UNION
SELECT 11, 'date', to_char(v_date), dump(v_date) FROM dual UNION
SELECT 12, 'timestamp', to_char(v_timestamp), dump(v_timestamp) FROM dual UNION
SELECT 13, 'long', to_char(v_long), dump(v_long) FROM dual
) t;
end;
事务
包含多个SQL语句操作的具有原子性的逻辑单元
set transaction开始
结束:
- commit / rollback
- 隐式commit(ddl)
- IDE或者工具的正常退出
- 连接异常中断
ACID,原子性、一致性、隔离性、持久性
锁
独占锁、共享锁
行锁(独占)和表锁(共享)
死锁
预防死锁
- 避免长事务,减少锁的等待时间
- 合理处理并发
避免在plsql使用for update进行数据库修改,忘记处理事务就要死锁了
查死锁
SELECT l.session_id sid,
s.serial#,
l.locked_mode,
l.oracle_username,
l.os_user_name,
s.machine,
s.terminal,
o.object_name,
s.logon_time,
p.SPID
FROM v$locked_object l, all_objects o, v$session s,v$process p
WHERE l.object_id = o.object_id
AND l.session_id = s.sid
AND s.paddr = p.addr
ORDER BY sid, s.serial#;
删死锁
-- 方法 alter system kill session 'sid,serial#'
alter system kill session '26,7013';
表结构
创建表
1、创建5.0的表空间
create tablespace yy50_data
logging
datafile '/u01/app/oracle/oradata/orcl/YY50.dbf'
size 50m
autoextend on
next 50m maxsize 20480m
extent management local;
2、创建用户
create user yy50 identified by oracle
default tablespace yy50_data;
3、为yy50用户赋权限
grant connect, resource,dba to yy50;
如果没有表空间权限
select * from dba_data_files
select tablespace_name from dba_tablespaces ;
create user C##TCS identified by oracle
default tablespace LXFINOTS202203;
grant connect, resource,dba to C##TCS;
视图
-- 创建
CREATE VIEW ot_tdictionary_simple_view AS
SELECT
L_KEY_NO,
VC_KEY_VALUE
FROM
ot_tdictionary;
-- 删除
DELETE view ot_tdictionary_simple_view;
-- 查看结构
select text from user_views where view_name='viewName'
索引
declare
v_rowcount integer ;
begin
select count(1) into v_rowcount from USER_INDEXES where upper(INDEX_NAME) = upper('IREQUESTDETAIL_HKCAPITALMODE')
and upper(TABLE_NAME) = upper('TC_TREQUESTDETAIL');
if v_rowcount = 0 then
execute IMMEDIATE 'create index IREQUESTDETAIL_HKCAPITALMODE on TC_TREQUESTDETAIL (C_HK_CAPITAL_MODE)';
end if
end;
/
create [unique | bitmap] index [schema.] 索引名
on [schema.] 表名 (列名1, .., 列名N);
1. 创建 '一般索引'('B-Tree' 索引)
create index scott.idx_si_sname on scott.student_info(sname);
create index scott.idx_si_sname_age on scott.student_info(sname, sex);
2. 创建 '位图索引'
create bitmap index scott.bidx_si_sex on scott.student_info(sex);
1. 查询索引
select t.*
from dba_indexes t
where t.owner = 'SCOTT'
and t.table_name = 'STUDENT_INFO';
2. 修改索引
-- 修改索引名称 idx_si_sname -> idx_si_sname_new
alter index scott.idx_si_sname rename to idx_si_sname_new;
-- 修改索引为无效
alter index scott.idx_si_sname_new unusable;
-- 重建索引
alter index scott.idx_si_sname_new rebuild online;
3. 删除索引
drop index scott.idx_si_age;
函数
https://www.cnblogs.com/zougang/p/9209706.html
create or replace function GetNextWorkDay_tmp(v_currentdate IN varchar2)
return varchar is Result varchar2(10);
begin
select to_char(min(d_date), 'yyyymmdd')
into Result
from tc_topenday_tmp t
where t.d_date > to_date(v_currentdate, 'yyyy-mm-dd')
and t.l_work_flag = 1;
return(Result);
end GetNextWorkDay_tmp;
select GetNextWorkDay_tmp('20221221') from dual;
语句少了分号,看了半天
存储过程
一组完成特定功能的PL/SQL语句集
优点:
- 降低网络通讯量
- 提高执行效率,编译过了
- 可修复性高
- 简化流程
缺点:
- 数据库移植不方便
- 不支持面向对象
- 维护性差,不支持集群
基础结构
存储过程包括:过程声明、执行过程部分、存储过程异常
无参数
CREATE
OR REPLACE PROCEDURE mingTest
AS
icount number;
begin
select count(1) into icount from user_tab_cols;
if icount = 1 then
dbms_output.put_line(icount);
else
dbms_output.put_line('---');
end if;
exception
when too_many_rows then
DBMS_OUTPUT.PUT_LINE('返回值多于1行');
when others then
DBMS_OUTPUT.PUT_LINE('在RUNBYPARMETERS过程中出错!');
end mingTest;
BEGIN
mingTest;
END;
有参
create or replace procedure runbyparmeters
(isal in emp.sal%type,
sname out varchar,
sjob in out varchar)
as
icount number;
begin
select count(*) into icount
from emp
where sal > isal and job = sjob;
if icount = 1 then
-- ....
else
-- ....
end if;
exception
when too_many_rows then
DBMS_OUTPUT.PUT_LINE('返回值多于1行');
when others then
DBMS_OUTPUT.PUT_LINE('在RUNBYPARMETERS过程中出错!');
end;
其中参数IN表示输入参数,是参数的默认模式。
OUT表示返回值参数,类型可以使用任意Oracle中的合法类型。
OUT模式定义的参数只能在过程体内部赋值,表示该参数可以将某个值传递回调用他的过程
IN OUT表示该参数可以向该过程中传递值,也可以将某个值传出去。
样例
实例
-- 将column_name属性相同的分组,并将table_name拼接,逐条插入ming_temp_table1表中
CREATE
OR REPLACE PROCEDURE mingTest AS
str_sql varchar2(4000);
same_count number;
TYPE ref_cursor_type IS REF CURSOR;
one_group_cur ref_cursor_type;
table_names varchar2(4000);
table_name varchar2(4000);
BEGIN
DECLARE
-- column_name属性不同的组
CURSOR cur_group IS
SELECT
t3.COLUMN_NAME,
t3.DATA_TYPE,
t3.DATA_LENGTH
FROM
user_tab_cols t3
WHERE
EXISTS (
SELECT
t2.COLUMN_NAME
FROM
(
SELECT
t1.COLUMN_NAME
FROM
(
SELECT
t.COLUMN_NAME,
t.DATA_TYPE,
t.DATA_LENGTH
FROM
user_tab_cols t
GROUP BY
t.COLUMN_NAME,
t.DATA_TYPE,
t.DATA_LENGTH
) t1
GROUP BY
t1.COLUMN_NAME
HAVING count(1) >= 2
) t2
WHERE t2.COLUMN_NAME = t3.COLUMN_NAME
)
group BY
t3.COLUMN_NAME, t3.DATA_TYPE, t3.DATA_LENGTH;
BEGIN
DBMS_OUTPUT.ENABLE(buffer_size => null);
-- str_sql := 'drop table ming_temp_table1';
-- execute immediate str_sql;
-- 创建临时表
-- str_sql := 'create global temporary table ming_temp_table1 (
-- COLUMN_NAME varchar2(200),
-- DATA_TYPE varchar2(200),
-- DATA_LENGTH varchar2(100),
-- TABLE_NAMES varchar2(4000)
-- ) on commit preserve rows';
-- execute immediate str_sql;
-- 遍历存在column_name属性不同的组
FOR group_row IN cur_group
loop
table_names := '';
-- 查询同组内的table_name
str_sql := 'select TABLE_NAME from user_tab_cols where COLUMN_NAME = ''' || group_row.COLUMN_NAME || ''' and DATA_TYPE = ''' || group_row.DATA_TYPE || ''' and DATA_LENGTH = ''' || group_row.DATA_LENGTH || '''';
-- 游标拼接同组的table_name
open one_group_cur for str_sql;
loop
fetch one_group_cur into table_name;
exit when one_group_cur%notfound;
table_names := ltrim(table_names || ' , ' || table_name, ' , ');
end loop;
str_sql := 'insert into ming_temp_table1(COLUMN_NAME, DATA_TYPE, DATA_LENGTH, TABLE_NAMES) values(''' || group_row.COLUMN_NAME || ''',''' || group_row.DATA_TYPE || ''', ''' || group_row.DATA_LENGTH || ''', ''' || table_names || ''')';
execute immediate str_sql;
END loop;
-- 删除临时表
-- str_sql := 'drop table ming_temp_table1';
-- execute immediate str_sql;
commit;
END;
END mingTest;
-- 运行存储过程
BEGIN
mingTest;
END;
-- 获取column_name相同属性的表信息
select * from ming_temp_table1 order by column_name, DATA_TYPE, DATA_LENGTH;
select * from user_tab_cols where table_name = 'MING_TEMP_TABLE' ;
delete from ming_temp_table1
drop table ming_temp_table1
select t.COLUMN_NAME,
t.DATA_TYPE,
t.DATA_LENGTH, t.rownum from(
select * from (
select * from user_tab_cols
where DATA_TYPE != 'VARCHAR2'
) t
group by t.COLUMN_NAME, t.DATA_TYPE, t.DATA_LENGTH, t.DATA_SCALE
) t where rownum < 10;
desc TC_TCHARGEACCOREQUEST;
变量
标量类型
CLOB长文本
常用:NUMBER、CHAR 、VARCHAR2 、VARCHAR、NCHAR 、NVARCHAR2 、LONG 、DATE 、TIMESTAMP
%TYPE 利用已经存在的数据类型来定义新数据的数据类型
例如,当定义多个变量或常量时,只要前面使用过的数据类型,后边的变量就可以利用%TYPE 引用
一组完成数据库功能的SQL语句集。
sex LY_DS.LY_NB%TYPE ,变量sex,它的类型与表LY_DS中的字段LY_NB 类型一致。
复合类型
记录类型
countNum number(10); --别忘了写上具体的长度,并且以分号结束
maxId number(10); --别忘了写上具体的长度,并且以分号结束
select count(*), max(id) into countNum, maxId from ly_ds where LY_NB=sex;
(1).type声明,类似对象
DECLARE
TYPE new_type IS RECORD --以TYPE type_name IS RECORD开始
(
v_ly_nl LY_DS.LY_NL%TYPE,
v_ly_mc varchar(100) --最后不要加,
); --最后以 ;结束
v_obj new_type; --将新对象定义为刚才声明的类型
BEGIN
--into赋值给v_obj,会按照定义的type顺序赋值
select ly_nl, ly_mc into v_obj from ly_ds where id = '2';
dbms_output.put_line('第一个变量:'||v_obj.v_ly_nl);
dbms_output.put_line('第二个变量:'||v_obj.v_ly_mc);
END;
(2).%rowtype,直接一整行当做对象
set serveroutput on;
DECLARE
v_obj ly_ds%rowtype; --ROWTYPE不区分大小写
BEGIN
--into赋值给v_obj,会按照定义的type顺序赋值
select * into v_obj from ly_ds where id='2';
-- v_obj.ly_nl
-- v_obj.ly_mc
END;
索引表类型
set serveroutput on;
DECLARE
/**
*声明一个存储ly_ds整行数据的索引表,下标为数字,
*/
type index_row_type is table of ly_ds%rowtype
index by binary_integer;
v_row index_row_type;
/**
*将某行数据赋值给行变量的下标1上
*/
select * into v_row(1) from ly_ds where id = '2';
dbms_output.put_line('v_row(1)中ly_mc的值:'||v_row(1).ly_mc);
dbms_output.put_line('v_row(1)中ly_nl的值:'||v_row(1).ly_nl);
/**
*声明一个存储字符串数据的索引表,下标也为数字,
*/
type index_val_type is table of varchar2(10)
index by pls_integer;
v_val index_val_type;
v_val(1) :='正数';
/**
*声明一个存储字符串数据的索引表,下标为字符串,
*即 varchar(100)、varchar(10),必须给固定大小
*/
type index_str_val_type is table of varchar2(100)
index by varchar(10);
v_str_val index_str_val_type;
v_str_val('test1') :='java太可怕了';
BEGIN
-- 以上的数据赋值
END;
varry定长数组
下边从1开始,要初始化,使用前要确定容量
DECLARE
/**
*声明一个最多容纳100个数的varry数组,注意,它的下标是从1开始的。
*即 binary_integer
*/
type array_type is varray(100) of varchar(100);
/**
*分别定义一个直接赋值的和两个未赋值的数组。
*注意:一定要初始化,但可以不赋值。对于没有赋值的这种数组,在用之前
*也一定要先确定容量。
*/
v_val_array array_type := array_type('one','two');
v_val_array2 array_type := array_type();
v_val_array3 array_type := array_type();
BEGIN
-- v_val_array(1)
-- v_val_array(2)
/**
*第二个varry没有初始化长度,所以通过extend方法,为该数组加一个空位
*/
v_val_array2.extend;
v_val_array2(1) :='aaa';
v_val_array2.extend;
v_val_array2(2) :='bbb';
v_val_array2.extend;
v_val_array2(3) :='ccc';
v_val_array3.extend(v_val_array2.count());
v_val_array3(3) :='fff';
END;
CRUD样例
create or replace procedure test_add_procedure
(id varchar,createtime varchar,name varchar,
age varchar,sex varchar)
AS
str_sql varchar2(4000);
BEGIN
insert into ly_ds values(id,createtime,name,age,sex);
update ly_ds set ly_mc = mc where id = dsId ;
select count(*),max(id) into countNum,maxId from ly_ds where LY_NB=sex;
str_sql := 'insert into ming_temp_table1() xxxx';
execute immediate str_sql;
commit; --别忘了加提交
end;
-- 单独执行
call test_add_procedure(4,'2018-08-09','李四','20','女');
call mingTest();
-- 程序块内执行
BEGIN
mingTest();
END;
游标
oracle存储过程—-游标(cursor)的学习_茁壮成长的凌大大的博客-CSDN博客_存储过程cursor用法
(2条消息) Oracle存储过程中游标的简单使用_峡谷修身养性的博客-CSDN博客_oracle存储过程游标
是SQL的内存工作区,临时存储从数据库中提取的数据块
隐式游标
增删改查 and
create or replace procedure test_cryptic_procedure
as
begin
for cryptic_rec in (
select * from ly_ds
)
loop
dbms_output.put_line('名称:'||cryptic_rec.ly_mc||' 年龄:'||cryptic_rec.ly_nl);
end loop;
end;
显式游标
显式游标分为静态游标和动态游标,一般包含:声明、打开、提取、关闭,游标使用完后,必须显式关闭。
隐式游标默认打开,执行完后自动关闭
动态
-- ref游标,动态关联结果集的临时对象,即在运行的时候动态决定执行查询
TYPE ref_cursor_type IS REF CURSOR;
one_group_cur ref_cursor_type;
DECLARE
-- column_name属性不同的组
CURSOR cur_group IS select xxxx;
-- 游标遍历
FOR group_row IN cur_group
loop
table_names := '';
-- 查询同组内的table_name
str_sql := 'select TABLE_NAME from user_tab_cols where COLUMN_NAME = ''' || group_row.COLUMN_NAME || ''' and DATA_TYPE = ''' || group_row.DATA_TYPE || ''' and DATA_LENGTH = ''' || group_row.DATA_LENGTH || '''';
-- 游标拼接同组的table_name
open one_group_cur for str_sql;
loop
fetch one_group_cur into table_name;
exit when one_group_cur%notfound;
table_names := ltrim(table_names || ' , ' || table_name, ' , ');
end loop;
str_sql := 'insert into ming_temp_table1(COLUMN_NAME, DATA_TYPE, DATA_LENGTH, TABLE_NAMES) values(''' || group_row.COLUMN_NAME || ''',''' || group_row.DATA_TYPE || ''', ''' || group_row.DATA_LENGTH || ''', ''' || table_names || ''')';
execute immediate str_sql;
END loop;
游标例子
CREATE
OR REPLACE PROCEDURE test_select3_procedure ( sex VARCHAR ) AS --游标的定义
Cursor test_cursor IS SELECT
id,
ly_mc,
LY_NB
FROM
ly_ds
WHERE
LY_NB = sex;
cur test_cursor%rowtype; --游标的类型,类似于list的泛型
BEGIN
FOR cur IN test_cursor
loop
exit WHEN test_cursor % notfound;
dbms_output.put_line ( '数据是:' || cur.id || '_' || cur.ly_mc );
END loop;
END;
遍历游标
create or replace procedure myprocedure is
CURSOR CUR_TEST IS --声明显式游标
SELECT ECODE,ENAME
FROM EMP;
CUR CUR_TEST%ROWTYPE; --定义游标变量,该变量的类型为基于游标C_EMP的记录
BEGIN
--For 循环
FOR CUR IN CUR_TEST LOOP
--循环体
DBMS_OUTPUT.PUT_LINE('员工编号:'||CUR.ECODE ||'员工姓名:'|| CUR.ENAME);
END LOOP;
--Fetch 循环
OPEN CUR_TEST;--必须要明确的打开和关闭游标
LOOP
FETCH CUR_TEST INTO CUR;
EXIT WHEN CUR_TEST%NOTFOUND;
--循环体
DBMS_OUTPUT.PUT_LINE('员工编号:'||CUR.ECODE ||'员工姓名:'|| CUR.ENAME);
END LOOP;
CLOSE CUR_TEST;
--While 循环
OPEN CUR_TEST;--必须要明确的打开和关闭游标
FETCH CUR_TEST INTO CUR;
WHILE CUR_TEST%FOUND LOOP
--循环体
DBMS_OUTPUT.PUT_LINE('员工编号:'||CUR.ECODE ||'员工姓名:'|| CUR.ENAME);
FETCH CUR_TEST INTO CUR;
END LOOP;
CLOSE CUR_TEST;
END myprocedure;
流程控制
赋值i := 0
判断相等i = 0
判断不等i <> 0
if 、elsif 、else 、end if
create or replace procedure test_select5_procedure
(innum number,outnum out number)
AS
BEGIN
if (innum > 5) then --(判断条件是否大于5 ,满足条件则以then标识进入当前分支)
if(innum = 10) then -- (= 为相等)
outnum := 20; -- (:= 表示赋值)
else
outnum := innum + 1 ;
end if; --- (每个分支的结束都以 end if;来结束)
dbms_output.put_line('第一个分支:'||outnum);
elsif (innum > 0) then --- (elsif 的写法注意,亲测必须这么写才行,写成else if不行的)
outnum := innum - 1 ;
dbms_output.put_line('第二个分支:'||outnum);
else
outnum := -1 ;
dbms_output.put_line('第三个分支:'||outnum);
end if; --- (每个分支的结束都以 end if;来结束)
END;
case
简单case
CREATE
OR REPLACE PROCEDURE test_case_procedure
( idnum VARCHAR )
AS
v_ly_ds ly_ds % rowtype;
BEGIN
SELECT *
INTO v_ly_ds
FROM
ly_ds
WHERE
id = idnum;
CASE v_ly_ds.ly_nb
WHEN '女' THEN
dbms_output.put_line ( '女人' );
WHEN '男' THEN
dbms_output.put_line ( '男人' );
ELSE dbms_output.put_line ( '人妖' );
END CASE;
END;
搜索case,case后边没有参数
select *
into v_ly_ds
from ly_ds
where id=idnum;
case
when v_ly_ds.ly_nb='女' then
dbms_output.put_line('女人');
when v_ly_ds.ly_nb='男' then
dbms_output.put_line('男人');
else
dbms_output.put_line('人妖');
end case;
异常
预定义异常
-- 查看oracle预定义的异常
SELECT * FROM DBA_SOURCE WHERE NAME='STANDARD' AND TEXT LIKE '%EXCEPTION_INIT%'
自定义异常
exception
when too_many_rows then
DBMS_OUTPUT.PUT_LINE('返回值多于1行');
when others then
DBMS_OUTPUT.PUT_LINE('在RUNBYPARMETERS过程中出错!');
临时表
create or replace procedure pro as
str_sql varchar2(100);
begin
-- 创建临时表
str_sql := 'create global temporary table temp_table (
col1 varchar2(10),
col2 number
) on commit preserve rows';
execute immediate str_sql;
-- 使用临时表
str_sql := 'insert into temp_table(col1, col2) values(''a'', 1)';
execute immediate str_sql;
-- 删除临时表
str_sql := 'drop table temp_table';
execute immediate str_sql;
end;
查看SQL
-- 查看所有存储过程
select distinct name From user_source where type = 'PROCEDURE'
-- 查看内容
SELECT text
FROM user_source
WHERE NAME = 'PRC_APP_GETTALENTALLARTICLES'
ORDER BY line
;
-- 复制去除空行,https://uutool.cn/nl-trim/
其他
初始化
CREATE TABLESPACE FS50_MINGYUE
LOGGING
DATAFILE '/home/oracle/FS50.DBF'
SIZE 1024M
AUTOEXTEND ON
NEXT 50M
EXTENT MANAGEMENT LOCAL;
CREATE USER c##_mingyue_tcs IDENTIFIED BY mingyue DEFAULT TABLESPACE FS50_MINGYUE TEMPORARY TABLESPACE TEMP;
GRANT
CREATE SESSION,
UNLIMITED TABLESPACE,
CREATE TABLE,
CREATE CLUSTER,
CREATE SYNONYM,
CREATE VIEW,
CREATE SEQUENCE,
CREATE DATABASE LINK,
CREATE PROCEDURE,
CREATE TRIGGER,
CREATE TYPE,
CREATE OPERATOR,
CREATE INDEXTYPE
TO c##_mingyue_tcs;
备份dmp
# 导出
expdp C##CS/ling@ORCLCDB dumpfile=221027.dmp
# 导入
impdp user_name/pwd@orcl dumpfile=xx.DMP log=xx.log
expdp userid=aaa/bbb directory=DMUP_DIR dumpfile=ccc.dmp schemas=aaa
expdp userid=aaa/bbb directory=DMUP_DIR dumpfile=ccc.dmp schemas=aaa
expdp C##TCS/libing@10.20.26.250:1521/ORCLCDB dumpfile=test.dmp ;
/opt/oracle/admin/ORCLCDB/dpdump
报错
报错:路径为空,是因为没有路径权限
ORA-39002: invalid operation
ORA-39070: Unable to open the log file.
ORA-39145: directory object parameter must be specified and non-null
http://blog.itpub.net/519536/viewspace-700840/
# dba进入
su - oracle
mkdir -p /home/oracle/database
sqlplus /nolog
connect /as sysdba
# sql中
create directory oracle_database_bak_dir as '/home/oracle/database';
grant read,write on directory oracle_database_bak_dir to public;
exit
# bash运行
expdp C##UPS/libing@ORCLCDB dumpfile=oracle_database_bak_dir:ups221027.dmp logfile=oracle_database_bak_dir:ups_database_log.log
备份
create table user_info_bak
as select * from user_info;
insert into user_info
select * from bosdata.user_info_bak;
常用工具
导出导入:exp/imp
- 简单,针对少量稳定数据
- 时间长,效率低
数据泵导出导入:expdp/impdp
- 简单,效率高,可以控制进程
手动备份和恢复
RMAN备份和恢复(自动,只备份有数据的数据块)
ash报告信息收集
exp 用户名/密码@连接串 file=test.dmp tables=test rows=y
exp C##tcs/libing@10.20.26.250/ORCLCDB file=city_test.dmp tables=L_TCITY rows=y
unl/sqlldr
- 建表
- ctl文件
- 运行
建表
CREATE TABLE L_TPROVINCE
(
VC_PROVINCE_CODE VARCHAR2(10) NOT NULL,
VC_PROVINCE_NAME VARCHAR2(32) NOT NULL);
ALTER TABLE L_TPROVINCE
ADD CONSTRAINT PK_L_TPROVINCE PRIMARY KEY (VC_PROVINCE_CODE);
ctl文件
load data infile 'D:\联行号\province.unl'
insert into table L_TPROVINCE
fields terminated by '|'
(VC_PROVINCE_CODE,
VC_PROVINCE_NAME)
运行
sqlldr 用户/密码@ip/xx control=sql.ctl direct=y log=log.log errors=5000 rows=500 bindsize=1048576
sqlldr C##tcs/libing@10.20.26.250/ORCLCDB control=D:\联行号\province.ctl direct=y log=D:\联行号\province.log
日志检查
检查alter$sid.log
show parameter background_dump_dest
针对性检查
是否宕机过
是否出现ORA错误,
操作系统是否出错
- vi /var/log/message
是否过分使用交换分区
信息收集
- 故障时间
- 操作系统
- alterlog
- awr ash报告
- 事发top/cpu/内存/io信息
数据库的创建和删除,要使用工具,不能直接 rm
脚本的斜杆
如果是存储过程,那么遇到分号,就不能马上执行了。这个时候,就需要通过斜杠(/)来执行
备份
create table ${tableName}_bak as select * from ${tableName}
表空间
-- https://blog.csdn.net/by0920/article/details/90142920
-- 用户
select * from dba_users;
-- 会话
select username,sid,serial# from v$session;
alter system kill session '$sid,$serial';
-- 表空间
SELECT * FROM User_Tablespaces;
drop tablespace FS50 including contents AND datafiles;
select * from dba_data_files;
-- 用户 LCS_09 TCS_09
drop user LCS_09 cascade;
drop user TCS_09 cascade;
字符编码
-- sql
select * from nls_database_parameters where parameter='NLS_CHARACTERSET';
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER SYSTEM ENABLE RESTRICTED SESSION;
ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;
ALTER SYSTEM SET AQ_TM_PROCESSES=0;
ALTER DATABASE OPEN;
ALTER DATABASE CHARACTER SET INTERNAL_USE ZHS16GBK; -- 跳过超子集检测
-- ? ALTER DATABASE national CHARACTER SET INTERNAL ZHS16GBK
SHUTDOWN IMMEDIATE;
STARTUP
连接数
https://blog.csdn.net/tianqishu11/article/details/78615850
- 以sysdba身份登陆PL/SQL
sqlplus / as sysdba;
-- 查看当前连接进程数
SQL>select count(*) from v$process;
-- 查看连接数上限
SQL>select value from v$parameter where name = 'processes';
-- 查询processes数量
SQL> show parameter processes
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
aq_tm_processes integer 0
db_writer_processes integer 3
gcs_server_processes integer 0
job_queue_processes integer 10
log_archive_max_processes integer 2
processes integer 150
-- 查询sessions数量
SQL> show parameter sessions
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
java_max_sessionspace_size integer 0
java_soft_sessionspace_limit integer 0
license_max_sessions integer 0
license_sessions_warning integer 0
logmnr_max_persistent_sessions integer 1
sessions integer 170
shared_server_sessions integer
SQL>
经过以上数据库参数查询,发现sessions数量不够,只有150,故增大sessions数量。
只要会话连接数超过上面的process数150或者sessions数170,再来一个的会话进程,就会产生12516错误。因此可以修改一下该值。sessions和processes关系必须按照如下关系设置。
sessions=1.1processes+5;
//这个是sessions值和processes值的关系,最好按照这样做,因此如果要将processes数设置为500,则sessions数必须为1.1500+5=555
修改连接数的限制
-- 以sysdba身份登陆PL/SQL
-- 查询目前连接数
show parameter processes;
-- 修改processes
alter system set processes=500 scope=spfile;
-- 修改session
alter system set sessions=555 scope=spfile;
-- 重启Oracle服务或重启Oracle服务器
-- 然后reboot数据库,使其生效
postGreSQL
官网:https://www.postgresql.org/about/
语法:https://www.runoob.com/postgresql/postgresql-syntax.html
from:https://blog.csdn.net/mr_door/article/details/102527225
下载:https://www.runoob.com/postgresql/windows-install-postgresql.html
介绍
优势:
- 稳定性强
- 免费开源,BSD协议,mysql开源,但是实际上是能被oracle公司控制的,如果和oracle市场冲突,必然会牺牲mysql
- 分布式环境好,集群架构,读写分离、负载均衡、数据水平拆分
- 源代码易读,容易二次开发
- 多进程,充分利用cpu,高并发逼近极限时,性能维持对数曲线,不再下降
- pg的text无限长,可以直接访问(一般关系型限定8k),sql语法内置正则、索引、全文检索、xml xpath
差异
http://hsfs-kb.hundsun.com/pages/viewpage.action?pageId=36274213
原生pg没适配oracle、mysql
类型强校验,numeric转integer也不行
entity str ---> db int or other,最佳实践: 增加jdbc连接参数stringtype=unspecified,该参数可让pg数据库会动尝试做合适的类型转换,程序中正常全都使用String类型即可。 specify the type to use when binding PreparedStatement parameters set via setString(). If stringtype is set to varchar(the default), such parameters will be sent to the server as varchar parameters. If stringtype is set to unspecified, parameters will be sent to the server as untyped values, and the server will attempt to infer an appropriate type. This is useful if you have an existing application that uses setString() to set parameters that are actually some other type, such as integers, and you are unable to change the application to use an appropriate method such as setInt(). # 会将string类型交给pg进行类型转换 例:jdbc连接串 db.config.datasource.trans2.jdbcurl=jdbc:postgresql://20.198.116.333:5432/ifm60_trans2?stringtype=unspecified&useUnicode=true&characterEncoding=UTF-8&useCursorFetch=true&useSSL=false
但添加stringtype=unspecified后部分函数会出问题,
- 如concat需在变量后指定类型.
如原语句是 concat(#{xxxx}, ‘1’) 需改为concat(#{xxxx}<if test="_databaseId=='postgresql'">::text</if>,'1')
- 如原语句是 case when #{xxxx} is null then ‘’ else #{xxxx} end as xxx 的写法也直接用mybatis判断变量是否为空,而不需要通过case when语句
- 如concat需在变量后指定类型.
不支持blob和clob,要用text/bytea
时间sysdate()、sysdate等无法使用
- now(),转数字CAST(to_char(now(), ‘YYYYMMDDHH24MISS’) AS BIGINT);
- 精确时间to_char(CURRENT_TIMESTAMP,’YYYYMMDDHH24MISS’)
- 日期to_char(CURRENT_TIMESTAMP,’YYYYMMDDHH24MISS’)
原生pg不支持rownum
- limit 1 offset 0(不支持start,size写法,建议mysql也用limt offset)
- ROW_NUMBER() over()
原生PG不支持rowid
- 一般用ctid
- 但oracle的rowid是固定不变的,而PG的ctid在重新收集统计信息后可能会变,一般在使用上两者可以等同
原生pg的update语句在set子句上不能用别名
- 如t.xxx
连表更新
- 只能update一个表,关联表要放在from子句里
- form查出要更新的数据,主表where关联
游标
- 写法不同
- 并且游标只能在存储过程里用
原生pg没有NVL、INSTR,不支持decode(有一个decode函数,但用法不同)
可以创建函数
CREATE OR REPLACE FUNCTION nvl(sourceVal text, defaultVal text) RETURNS text AS $body$ declare BEGIN RETURN case when sourceVal is null or sourceVal='' then defaultVal else sourceVal end; END; $body$ LANGUAGE plpgsql;
原生PG不支持dual
原生PG不支持CALL调用,直接select
for update不能用在left join右边为空的情况
表名和约束名constraint不能一样,否则建表失败
(select nextval(#{sequence})),貌似会缓存,因为sql已经被确定为某个值
<if test="_databaseId == 'oracle' or _databaseId == 'mysql' ">
</if>
<if test="_databaseId == 'postgresql'">
</if>
<if test="_databaseId == 'postgresql'">::text</if>
<select id="" resultMap="" databaseId="postgresql">
</select>
<select id="" resultMap="" databaseId="oracle">
</select>
类型
https://www.postgresql.org/docs/current/datatype.html
类型转换
select 233::text;
select text '233';
select text'233';
select cast(233 as numeric); -- as integer
-- numeric , 与integer不兼容
to_number('')
字符类型
序号 | 名字 & 描述 |
---|---|
1 | character varying(n), varchar(n)变长,有长度限制 |
2 | character(n), char(n)定长,不足补空白 |
3 | text变长,无长度限制 |
默认为普通字符串,不存在转义字符,但是mysql存入时会自动进行转义,将\\
转为\
,postgresql在9之后如果要当做转义字符,需要添加#'\\data'
如果要导入mysql的进入postgresql,需要将\\
替换为\
数值类型
名字 | 存储长度 | 描述 | 范围 |
---|---|---|---|
smallint | 2 字节 | 小范围整数 | -32768 到 +32767 |
integer | 4 字节 | 常用的整数 | -2147483648 到 +2147483647 |
bigint | 8 字节 | 大范围整数 | -9223372036854775808 到 +9223372036854775807 |
decimal | 可变长 | 用户指定的精度,精确 | 小数点前 131072 位;小数点后 16383 位 |
numeric | 可变长 | 用户指定的精度,精确 | 小数点前 131072 位;小数点后 16383 位 |
real | 4 字节 | 可变精度,不精确 | 6 位十进制数字精度 |
double precision | 8 字节 | 可变精度,不精确 | 15 位十进制数字精度 |
smallserial | 2 字节 | 自增的小范围整数 | 1 到 32767 |
serial | 4 字节 | 自增整数 | 1 到 2147483647 |
bigserial | 8 字节 | 自增的大范围整数 | 1 到 9223372036854775807 |
货币类型
money 类型存储带有固定小数精度的货币金额。
numeric、int 和 bigint 类型的值可以转换为 money,不建议使用浮点数来处理处理货币类型,因为存在舍入错误的可能性。
名字 | 存储容量 | 描述 | 范围 |
---|---|---|---|
money | 8 字节 | 货币金额 | -92233720368547758.08 到 +92233720368547758.07 |
JSON 类型
实例 | 实例结果 |
---|---|
array_to_json('{{1,5},{99,100}}'::int[]) |
[[1,5],[99,100]] |
row_to_json(row(1,’foo’)) | {“f1”:1,”f2”:”foo”} |
数组类型
PostgreSQL 允许将字段定义成变长的多维数组。
数组类型可以是任何基本类型或用户定义类型,枚举类型或复合类型。
声明数组
创建表的时候,我们可以声明数组,方式如下:
CREATE TABLE sal_emp (
name text,
pay_by_quarter integer[],
schedule text[][]
);
pay_by_quarter 为一维整型数组、schedule 为二维文本类型数组。
我们也可以使用 “ARRAY” 关键字,如下所示:
CREATE TABLE sal_emp (
name text,
pay_by_quarter integer ARRAY[4],
schedule text[][]
);
插入值
插入值使用花括号 {},元素在 {} 使用逗号隔开:
INSERT INTO sal_emp
VALUES ('Bill',
'{10000, 10000, 10000, 10000}',
'{{"meeting", "lunch"}, {"training", "presentation"}}');
INSERT INTO sal_emp
VALUES ('Carol',
'{20000, 25000, 25000, 25000}',
'{{"breakfast", "consulting"}, {"meeting", "lunch"}}');
访问数组
现在我们可以在这个表上运行一些查询。
首先,我们演示如何访问数组的一个元素。 这个查询检索在第二季度薪水变化的雇员名:
SELECT name FROM sal_emp WHERE pay_by_quarter[1] <> pay_by_quarter[2];
name
-------
Carol
(1 row)
数组的下标数字是写在方括弧内的。
修改数组
我们可以对数组的值进行修改:
UPDATE sal_emp SET pay_by_quarter = '{25000,25000,27000,27000}'
WHERE name = 'Carol';
或者使用 ARRAY 构造器语法:
UPDATE sal_emp SET pay_by_quarter = ARRAY[25000,25000,27000,27000]
WHERE name = 'Carol';
数组中检索
要搜索一个数组中的数值,你必须检查该数组的每一个值。
比如:
SELECT * FROM sal_emp WHERE pay_by_quarter[1] = 10000 OR
pay_by_quarter[2] = 10000 OR
pay_by_quarter[3] = 10000 OR
pay_by_quarter[4] = 10000;
另外,你可以用下面的语句找出数组中所有元素值都等于 10000 的行:
SELECT * FROM sal_emp WHERE 10000 = ALL (pay_by_quarter);
或者,可以使用 generate_subscripts 函数。例如:
SELECT * FROM
(SELECT pay_by_quarter,
generate_subscripts(pay_by_quarter, 1) AS s
FROM sal_emp) AS foo
WHERE pay_by_quarter[s] = 10000;
复合类型
复合类型表示一行或者一条记录的结构,相当于一个字段包含多个字段
它实际上只是一个字段名和它们的数据类型的列表。
像简单数据类型那样使用复合类型。比如,一个表的某个字段可以声明为一个复合类型。
声明复合类型
下面是两个定义复合类型的简单例子:
CREATE TYPE complex AS (
r double precision,
i double precision
);
CREATE TYPE inventory_item AS (
name text,
supplier_id integer,
price numeric
);
语法类似于 CREATE TABLE,只是这里只可以声明字段名字和类型。
定义了类型,我们就可以用它创建表:
CREATE TABLE on_hand (
item inventory_item,
count integer
);
INSERT INTO on_hand VALUES (ROW('fuzzy dice', 42, 1.99), 1000);
复合类型值输入
要以文本常量书写复合类型值,在圆括弧里包围字段值并且用逗号分隔他们。 你可以在任何字段值周围放上双引号,如果值本身包含逗号或者圆括弧, 你必须用双引号括起。
复合类型常量的一般格式如下:
'( val1 , val2 , ... )'
一个例子是:
'("fuzzy dice",42,1.99)'
访问复合类型
要访问复合类型字段的一个域,我们写出一个点以及域的名字, 非常类似从一个表名字里选出一个字段。实际上,因为实在太像从表名字中选取字段, 所以我们经常需要用圆括弧来避免分析器混淆。比如,你可能需要从on_hand 例子表中选取一些子域,像下面这样:
SELECT item.name FROM on_hand WHERE item.price > 9.99;
这样将不能工作,因为根据 SQL 语法,item是从一个表名字选取的, 而不是一个字段名字。你必须像下面这样写:
SELECT (item).name FROM on_hand WHERE (item).price > 9.99;
或者如果你也需要使用表名字(比如,在一个多表查询里),那么这么写:
SELECT (on_hand.item).name FROM on_hand WHERE (on_hand.item).price > 9.99;
现在圆括弧对象正确地解析为一个指向item字段的引用,然后就可以从中选取子域。
范围类型
着某一元素类型在一定范围内的值。
PostgreSQL 内置的范围类型有:
- int4range — integer的范围
- int8range —bigint的范围
- numrange —numeric的范围
- tsrange —timestamp without time zone的范围
- tstzrange —timestamp with time zone的范围
- daterange —date的范围
自定义
CREATE TABLE reservation (room int, during tsrange);
INSERT INTO reservation VALUES
(1108, '[2010-01-01 14:30, 2010-01-01 15:30)');
-- 包含
SELECT int4range(10, 20) @> 3;
-- 重叠
SELECT numrange(11.1, 22.2) && numrange(20.0, 30.0);
-- 提取上边界
SELECT upper(int8range(15, 25));
-- 计算交叉
SELECT int4range(10, 20) * int4range(15, 25);
-- 范围是否为空
SELECT isempty(numrange(1, 5));
数据库操作
程序jdbc:postgresql://xx.xx.xx.xx:15432/tcs?currentSchema=gaussdb
创建
CREATE DATABASE dbname;
选择
# 登录
psql -h localhost -p 5432 -U postgres runoobdb
psql -h localhost -p 5432 -U postgres postgres
psql -h 10.188.140.49 -p 5432 -U postgres postgres
psql -h 10.188.140.49 -p 5432 -U postgres -d postgres
# 查看数据库
\l
# 进入数据库
\c + 数据库名
连接无权限
https://blog.csdn.net/u013719339/article/details/78414188
# pg_hba.conf文件在Postgre安装文件目录下的data文件夹
# 末尾添加,重启
host all all 0.0.0.0/0 md5
删除
DROP DATABASE [ IF EXISTS ] name;
-- https://www.runoob.com/postgresql/postgresql-drop-database.html
dropdb [connection-option...] [option...] dbname;
表结构
查看
-- 查看表信息
-- 所有,可以接通配符
\d
\d tablename
select * from pg_tables;
SELECT tablename FROM pg_tables WHERE tablename NOT LIKE 'pg%' AND tablename NOT LIKE 'sql_%' ORDER BY tablename;
创建
CREATE TABLE table_name(
column1 datatype,
column2 datatype,
column3 datatype,
.....
columnN datatype,
-- constraint pk_test_a_id primary key( id)
PRIMARY KEY( 一个或多个列 )
);
CREATE TABLE COMPANY(
ID INT PRIMARY KEY NOT NULL,
NAME TEXT NOT NULL,
AGE INT NOT NULL,
ADDRESS CHAR(50),
SALARY REAL
);
-- 查看是否成功
\d
删除
DROP TABLE table_name;
drop table department, company;
\d
修改
-- add
ALTER TABLE table_name ADD column_name datatype;
-- delete
ALTER TABLE table_name DROP COLUMN column_name;
-- update
ALTER TABLE table_name ALTER COLUMN column_name TYPE datatype;
-- constraint not null
ALTER TABLE table_name ALTER column_name datatype NOT NULL;
-- constraint unique
ALTER TABLE table_name
ADD CONSTRAINT MyUniqueConstraint UNIQUE(column1, column2...);
-- constraint PRIMARY
ALTER TABLE table_name
ADD CONSTRAINT MyPrimaryKey PRIMARY KEY (column1, column2...);
-- constraint common delete
ALTER TABLE table_name
DROP CONSTRAINT MyUniqueConstraint;
-- mysql delete index,unique/primary key
ALTER TABLE table_name
DROP INDEX MyUniqueConstraint;
ALTER TABLE table_name
DROP PRIMARY KEY;
do
$$
begin
if (SELECT count(1) FROM pg_indexes WHERE upper(tablename) = 'LC_TRESULTNOTICECFG' AND upper(indexname) = 'IRESULTNOTICECFG') > 0 then
DROP INDEX iresultnoticecfg;
end if;
CREATE UNIQUE INDEX iresultnoticecfg ON LC_TRESULTNOTICECFG USING btree (vc_tenant_id, l_serial_no);
end;
$$;
commit;
视图
虚拟表
- 更自然直观的查找结构数据
- 限制数据访问,只能看到有限的数据
- 汇总各个表的数据
pg视图自读,无法执行delete/insert/update,但是可以创建触发器,尝试修改时触发。
CREATE [TEMP | TEMPORARY] VIEW view_name AS
SELECT column1, column2.....
FROM table_name
WHERE [condition];
DROP VIEW view_name;
触发器
触发场景:操作前、操作后,更新时
CREATE TRIGGER trigger_name [BEFORE|AFTER|INSTEAD OF] event_name
ON table_name
[
-- 触发器逻辑....
];
顺便插入日志
CREATE TRIGGER example_trigger AFTER INSERT ON COMPANY FOR EACH ROW EXECUTE PROCEDURE auditlogfunc();
CREATE OR REPLACE FUNCTION auditlogfunc() RETURNS TRIGGER AS $example_table$
BEGIN
INSERT INTO AUDIT(EMP_ID, ENTRY_DATE) VALUES (new.ID, current_timestamp);
RETURN NEW;
END;
$example_table$ LANGUAGE plpgsql;
-- 查看
SELECT * FROM pg_trigger;
SELECT tgname FROM pg_trigger, pg_class WHERE tgrelid=pg_class.oid AND relname='company';
-- 删除
drop trigger ${trigger_name} on ${table_of_trigger_dependent};
模式
PostgreSQL 模式(SCHEMA)可以看着是表的集合
使用模式的优势:
- 允许多个用户使用一个数据库并且不会互相干扰。
- 将数据库对象组织成逻辑组以便更容易管理。
- 第三方应用的对象可以放在独立的模式中,这样它们就不会与其他对象的名称发生冲突。
元数据
官网:https://www.postgresql.org/docs/15/catalogs.html
视图
INFORMATION_SCHEMA中的视图由SQL标准定义
SELECT column_name, data_type, character_maximum_length
FROM information_schema.columns
WHERE table_name = 'tsys_user'
系统表
pg_class
记录了数据库中的表,索引,序列,视图(“关系”)。
relname 表,索引,视图等的名字。
relnamespace 包含这个关系的名字空间(模式)的 OID,对应pg_namespace.oid
relkind r = 普通表,i = 索引,S = 序列,v = 视图, c = 复合类型,s = 特殊,t = TOAST表
pg_namespace
记录了数据库的名字空间(模式)
其中比较重要的字段有:
nspname 名字空间的名字
nspowner 名字空间的所有者
pg_attribute
记录了数据库关于表的字段的信息。
其中比较重要的字段有:
attrelid 此列/字段所属的表,对应于pg_class.oid
attname 字段名字
atttypid 这个字段的数据类型,对应于pg_type.oid
attlen 对于定长类型,typlen是该类型内部表现形式的字节数目。 对于变长类型,typlen 是负数。 -1 表示一种”变长”类型(有长度字属性的数据), -2 表示这是一个 NULL 结尾的 C 字串。是本字段类型 pg_type.typlen 的拷贝。
attnum 字段数目。普通字段是从 1 开始计数的。系统字段, 比如 oid, 有(任意)正数。
atttypmod atttypmod 元组在创建表的时候 提供的类型相关的数据(比如,一个 varchar 字段的最大长度)。 它传递给类型相关的输入和长度转换函数当做第三个参数。 其值对那些不需要 atttypmod 的类型而言通常为 -1。
attnotnull 这代表一个非空约束。我们可以改变这个字段以打开或者关闭这个约束。
attisdropped 这个字段已经被删除了,不再有效。
pg_type
typname
数据类型名字typlen
对于定长类型,typlen是该类型内部表现形式的字节数目。 对于变长类型,typlen 是负数。 -1 表示一种”变长”类型(有长度字属性的数据), -2 表示这是一个 NULL 结尾的 C 字串。
pg_description
记录了数据库中对象(表、字段等)的注释。
其中比较重要的字段有:
objoid 这条描述所描述的对象的 OID。如果这条注释是一个表或表中字段的注释,那么,该值对应于pg_class.oid
objsubid 对于一个表字段的注释,它是字段号,对应于pg_attribute.attnum。对于其它对象类型,它是零。
description 作为对该对象的描述的任意文本
常用SQL
select attr.attname, class.relname, type.typname, attr.atttypid, attr.*
from pg_attribute attr
left join pg_class class on class.oid = attr.attrelid
left join pg_type type on type.oid = attr.atttypid
where class.relname = 'test_table';
存储过程
function样例
无需创建即可执行function
do
$$
declare
test int;
begin
select count(*) into test from tc_tsysparameter;
end;
$$;
do
$$
DECLARE
d_news_id numeric;
d_tag_id numeric;
cur_list CURSOR FOR
select flu.id,fcm.id
FROM
a fcm,
b frr,
c flur,
d flu
WHERE
fcm.create_id = frr.relation_id
AND flur.ID = frr.role_id
AND flu.id = flur.login_user_id
AND fcm.create_id IS NOT NULL
AND flur.role_type = 1
AND flur.status = 1
AND frr. TYPE = 1;
BEGIN
OPEN cur_list;
LOOP
FETCH cur_list INTO d_news_id, d_tag_id;
EXIT WHEN NOT FOUND;
--插入数据
UPDATE a SET login_user_id = d_news_id where id = d_tag_id;
END LOOP;
CLOSE cur_list;
END;
$$;
样例
多条记录
create or replace function f_get_member_info(id integer)
--setof是关键字,暂时不清楚其作用;record是返回的数据类型,即“记录类型”数据;
returns setof record as
--两个美元符必须存在,中间可以填入符合命名规则的字符(如$body$,$abc$),但必须与下方的两个美元符相统一
$$
declare
rec record;--定义记录类型的变量,用于存储查询的结果
begin
--开始for循环,执行SELECT语句。注意,第一个loop后没有分号!
for rec in EXECUTE 'SELECT id,real_name FROM a_account_all' loop
return next rec;--将查询结果依次追加到rec变量中
end loop;--for循环结束
return;
end
$$
language 'plpgsql';
--调用存储过程f_get_member_info示例
-- a_account_all 为存储过程中被查询的表,id和real_name是表中的字段,也是在存储过程中被查询的字段
SELECT * FROM f_get_member_info(1568) as a_account_all(id integer,real_name character varying(50));
事务
begin;
-- or
BEGIN TRANSACTION;
备份
pg_dump -h127.0.0.1 -U postgres ots_09 > /mingyue_pg_.sql
其他
postgresql.conf max_connections
运行此 SQL 以查看允许的 postgresql 最大连接数:
show max_connections;
默认值为 100。良好硬件上的 PostgreSQL 一次可以支持几百个连接。如果你想拥有数千个,你应该考虑使用连接池软件来减少连接开销。
看看究竟是谁/什么/何时/何地打开了您的连接:
SELECT * FROM pg_stat_activity;
当前使用的连接数为:
SELECT COUNT(*) from pg_stat_activity;