Oracle与Greenplum
GP开发规范
对象数管控
严格控制数据库对象的数量(包括表,视图,索引,函数等),控制在2-3万以内性能最佳,最好不要超过5万,超过10万以后GP性能下降明显;(以下规范全部基于OLAP)
- 不允许建索引(包括普通索引、唯一索引、主键等);
- 临时表对象用完即时删除;
- 尽量不要建分区表,分区表会导致对象数急剧上升,建分区表考虑以几个问题:表是否足够大(上亿)?目前性能瓶颈?查询条件是否满足分区条件?是否需要滚动历史数据?数据能否被均匀分拆;
- 默认使用行存,列存会急剧增加对象数;
连接数管控
GP建议连接数控制在200个左右,连接数超过250个以后,GP性能明显下降,根据人数限制每个开发连接数个数,目前建议开发用户4个连接数;每隔30分钟杀掉开发用户超过30分钟不活跃的连接;
- 开发人员GP数据库连接数不超过4个;
建表管控
分布策略尽量使用分区分布,小的维度表可以使用复制表,大表禁止使用复制表;分区分布的分布键会影响后续查询效率,分布键没设置好,会导致数据倾斜或者查询时数据重分布;
GP中不加””时,不区分大小写,GP在数据字典中默认存为小写,如果需要区分大小写或者表名中存在特殊字符,请加上””;
GP中默认建Heap表(堆表),不能压缩,只能行存,适合数据量不大的表(维表等);AO(Append Optimized 追加优化表),可以压缩,对批量插入做了优化,适合大表(事实表等);
GP中标识符长度不超过63,ORACLE中标识符长度不超过30;
GP中char和varchar没有性能差异;
- 建表时必须手动指定分布键,大表(事实表等)最好使用经常关联的字段作为分布键,小表(维表等)最好使用主键作为分布键;
- 不允许使用默认分布键,尽可能不要使用随机分布策略;
- 分布键原则上为1个字段,尽量不要超过3个字段;
- 表名尽量使用数字、字母、下划线,不建议使用特殊字符;
- 千万行级别以下的表建Heap表,千万行以上级别的表建oa表,固定zstd压缩,压缩等级3,
WITH (APPENDONLY=true, COMPRESSTYPE=zstd, COMPRESSLEVEL=3); - GP中标识符长度不超过63,ORACLE中标识符长度不超过30;
- varchar类型替代char类型;
查询管控
GP中通过配置的模式搜索路径对对象进行搜索,默认搜索 “$user”,public;
GP中的除法运算需特别小心,select 1/2 的结果是0;
- 引用其它schema下的对象时,需要追加schemaname,例如:tool.tmp;
- 涉及到复合运算并且包含除法运算时,请在分子上添加1.0,例如:select 1/2 请改写成 select 11.0/2;
- 避免使用标量子查询,效率很低,并且容易造成表的死锁,需改成关联查询,例如:select a.id,(select b.name from tmp1 b where a.id = b.id) as name from tmp a 改成 select a.id,b.name from tmp a, tmp1 b where a.id = b.id ;
- 一个sql中多表关联不要超过10张表;
- sql语句全部小写;
简单的PSQL命令
psql常用参数
命令 | 说明 |
---|---|
psql -d etl -E -U tool -W -h 10.75.41.115 -p 5432 |
以tool用户登录到10.75.41.115主机上5432端口下的etl数据库,并且回显\d对应的sql语句 |
psql -d etl -U tool -W -h 10.75.41.115 -p 5432 -f xxxx.psql |
以tool用户登录到10.75.41.115主机上5432端口下的etl数据库执行xxxx.psql脚本 |
-d | 指定数据库名 |
-E | 回显由\d和其他反斜杠命令生成的实际查询 |
-U | 指定用户名 |
-W | 强制提示输入密码 |
-h | 主机名 |
-p | 端口 |
-f | 执行sql脚本 |
psql常用内部命令
命令 | 说明 |
---|---|
\connect etl tool |
以tool用户切换到etl数据库 |
\q |
退出psql客户端 |
\df |
查看所有的函数 |
\df tool.* |
查看tool下的函数 |
\dn |
查看所有的schemas |
\dt tool.* |
查看schema为tool下的所有的表 |
\d |
展示表的信息 |
\d+ |
比前面的\d 多了size和despription |
\dv gp_toolkit.gp_resq* |
查看资源组的视图 |
\du+ |
查看用户信息 |
\set |
设置替代变量 |
\! |
执行外部命令 |
语法
DDL
操作 | Oracle | GP |
---|---|---|
创建非分区表 | CREATE TABLE test( id NUMBER, name VARCHAR2(40) ); |
create table test( id int, name varchar(40) ) distributed by (id); |
创建分区表 | CREATE TABLE test( id NUMBER, name VARCHAR2(40), birth_day DATE ) PARTITION BY RANGE(birth_day)( PARTITION p20090101 VALUES LESS THAN (TO_DATE(‘20090102’,‘yyyymmdd’)), PARTITION p20090102 VALUES LESS THAN (TO_DATE(‘20090103’,‘yyyymmdd’)), PARTITION p20090103 VALUES LESS THAN (TO_DATE(‘20090104’,‘yyyymmdd’)) ); |
create table test(id int, name varchar(40), birth_day date ) distributed by (id) partition by range(birth_day)( partition p20090101 start(date ‘20010101’) inclusive, partition p20090102 start(date ‘20090102’) inclusive, partition p20090103 start(date ‘20090103’) inclusive end (date ‘20090104’) exclusive ); |
分区表增加分区 | ALTER TABLE test ADD PARTITION p20090104 VALUES LESS THAN (TO_DATE(‘20090105’,‘yyyymmdd’)); |
alter table test add partition p20090104 start (date ‘2009-01-04’) inclusive end (date ‘2009-01-05’) exclusive; |
分区表删除分区 | ALTER TABLE test DROP PARTITION p20090104; | alter table test drop partition p20090104; |
分区表截断分区 | ALTER TABLE test TRUNCATE PARTITION p20090101; | alter table test truncate partition p20090101; |
分区表分裂分区 | ALTER TABLE test SPLIT PARTITION p200905_mon AT (TO_DATE(‘20090515’,‘yyyymmdd’)) INTO ( PARTITION p200905_01, PARTITION p200905_02 ); |
alter table test split partition p200905_mon at (‘20090515’) into( partition p200905_01, partition p200905_02 ); |
删除表 | DROP TABLE test; | drop table if exists test; |
重命名表 | rename a to b; | alter table a rename to b; |
截断表 | TRUNCATE TABLE test; | truncate table test; |
创建索引 | CREATE INDEX idx_test ON test(id); | create index idx_test on test(id); |
创建主键 | ALTER TABLE test ADD CONSTRAINT pk_test PRIMARY KEY (id); | alter table test add constraint pk_test primary key (id); |
删除主键 | ALTER TABLE test DROP CONSTRAINT pk_test; | alter table test drop constraint if exists pk_test; |
删除索引 | DROP INDEX IND_TEST; | drop index if exists ind_test; |
添加字段 | ALTER TABLE test add ( column1 number, column2 varchar2(100) ); |
alter table test add column1 numeric, add column2 varchar(10); |
修改字段 | ALTER TABLE test modify (column1 VARCHAR2(100)); | alter table test alter column column1 type varchar(100); alter table test alter column1 type varchar(100); |
删除字段 | ALTER TABLE test DROP COLUMN column1; | alter table test drop column if exists column1; alter table test drop if exists column1; |
字段重命名 | ALTER TABLE test RENAME COLUMN column2 TO column1; | alter table test rename column column2 to column1; alter table test rename column2 to column1; |
创建视图 | CREATE VIEW v_test AS SELECT * FROM test; | create view v_test as select * from test; |
DML
操作 | Oracle | GP |
---|---|---|
插入记录 | INSERT INTO test VALUES (001,‘SUNWG’,TO_DATE(‘2009-01-01’,‘YYYY-MM-DD’)); | insert into test values (001,‘SUNWG’,‘2009-01-01’); |
删除记录 | DELETE FROM test WHERE id = 001; | delete from test where id = 001; |
关联更新记录 | UPDATE test a SET a.column1 = ( SELECT b.column1 FROM test1 b WHERE a.id = b.id ); |
update test a set column1 = b.column1 from test1 b where a.id = b.id; |
查询表中前10条记录 | SELECT * FROM test WHERE ROWNUM <= 10; | select * from test limit 10; |
两表内关联 | SELECT * FROM test1 a, test2 b WHERE a.id = b.id; | select * from test1 a inner join test2 b on (a.id = b.id); |
两表左外关联 | SELECT * FROM test1 a, test2 b WHERE a.id = b.id(+); | select * from test1 a left join test2 b on (a.id = b.id); |
事务提交 | INSERT INTO test VALUES (001,‘SUNWG’,TO_DATE(‘2009-01-01’,‘YYYY-MM-DD’)); COMMIT; |
begin; insert into test values (001,‘SUNWG’,‘2009-01-01’); commit; |
事务回滚 | INSERT INTO test VALUES (001,‘SUNWG’,TO_DATE(‘2009-01-01’,‘YYYY-MM-DD’)); ROLLBACK; |
begin; insert into test values (001,‘SUNWG’,‘2009-01-01’); rollback; |
数据类型转换 | SELECT to_number(‘101’) FROM dual; | select cast(‘101’ as numeric); select ‘101’ :: numeric; |
除法运算 | SELECT 1/2 FROM dual; | select 1.0/2; |
并集 | SELECT 1 FROM dual UNION SELECT 2 FROM dual; SELECT 1 FROM dual UNION ALL SELECT 2 FROM dual; |
select 1 union select 2; select 1 union all select 2; |
交集 | SELECT 1 FROM dual INTERSECT SELECT 1 FROM dual; |
select 1 intersect select 1; select 1 intersect all select 1; |
差集 | SELECT 1 FROM dual MINUS SELECT 2 FROM dual; |
select 1 except select 2; select 1 except all select 2; |
子查询 | SELECT * FROM (SELECT * FROM test); | select * from (select * from test) as a; |
日期抽取 | SELECT to_char(SYSDATE,‘yyyy-mm-dd’) FROM dual; | select to_char(current_timestamp,‘yyyy-mm-dd’); select extract(century from now()); --世纪 select extract(year from now()); --年 select extract(dow from now()); --星期几 select extract(dow from now()); --星期几 |
时间截取 | SELECT TRUNC(SYSDATE,‘hh’) FROM dual; | select date_trunc(‘hour’, now()); |
null和’’ | SELECT ‘123’||’’ FROM dual; --'123’ SELECT ‘123’||NULL FROM dual;–‘123’ |
select ‘123’||’’; --'123’ select ‘123’||null; --null |
delete 剔重 | DELETE FROM test a WHERE rowid < ( SEELCT MAX(rowid) FROM test b WHERE a.id = b.id ); |
delete from test a where ctid < ( select max(ctid) from test b where a.id = b.id and a.gp_segment_id = b.gp_segment_id ); |
当前的系统时间 | SELECT SYSDATE,current_timestamp FROM dual; | select current_timestamp,now(),clock_timestamp(); |
当前时间向前推一天 | SELECT SYSDATE-1 FROM dual; | select current_timestamp - interval ‘1 day’; |
当前时间向前推一个月 | SELECT add_months(SYSDATE,-1) FROM dual; | select current_timestamp - interval ‘1 month’; |
当前时间向前推一年 | SELECT add_months(SYSDATE,-12) FROM dual; | select current_timestamp - interval ‘1 year’; |
当前时间向前推一小时 | SELECT SYSDATE-1/24 FROM dual; | select current_timestamp - interval ‘1 hour’; |
当前时间向前推一分钟 | SELECT SYSDATE-1/24/60 FROM dual; | select current_timestamp - interval ‘1 min’; |
当前时间向前推30秒 | SELECT SYSDATE-1/24/60/60*30 FROM dual; | select current_timestamp - interval ‘30 second’; |
正则匹配 | SELECT 1 FROM dual WHERE regexp_like (‘123’,’[0-9]+’); | select 1 where ‘123’ ~ ‘[0-9]+’; |
正则截取 | SELECT regexp_substr(‘你好123’,’[0-9]+’) FROM dual; | select substring (‘你好123’ from ‘[0-9]+’); |
分区表查询指定分区 | SELECT * FROM test PARTITION (p20090101); | select * from test_1_prt_p20090101; |
字符串截取涉及非正数位置开始截取 | SELECT SUBSTR(‘12345’,-1,3) FROM dual; | select substr(‘12345’,length(‘12345’)-1+1,3); select substr(‘12345’,-1,3); --等价于 select substr(‘12345’,1,1); |
指定子字符串第一次出现的位置 | SELECT INSTR(‘123245’,‘24’,1,1) FROM dual | select strpos(‘123245’,‘24’); select position (‘24’ in ‘123245’); |
指定月份间相差的月份 | SELECT months_between(to_date(‘202108’,‘yyyymm’),to_date(‘202107’,‘yyyymm’)) FROM dual; | select extract( month from age( to_date(‘202108’,‘yyyymm’),to_date(‘202107’,‘yyyymm’) ) ) |
判空 | SELECT NVL(NULL,1) FROM dual; SELECT NVL(NULL,1) FROM dual; |
select coalesce (null::integer,1); |
序号 | SELECT ROWNUM,NAME FROM ( SELECT ‘ha’ NAME FROM dual UNION ALL SELECT ‘haha’ FROM dual ); |
select row_number() over(order by 1) xh,name from ( select ‘ha’ name union all select ‘haha’ ) a; |
to_char数字转换为字符 | select to_char(123,‘fm999’); | select to_char(123,‘fm999’); |
字符转换日期 | SELECT to_date(‘20210827’,‘yyyymmdd’) FROM dual; | select to_date(‘20210827’,‘yyyymmdd’); select to_timestamp(‘20210827’,‘yyyymmdd’); select cast (‘20210827’ as date); select cast (‘20210827’ as timestamp); |
字符转换为数字 | SELECT to_number(‘20210827’) FROM dual; | select cast(‘20210827’ as numeric); |
字符串分割 | SELECT kind, listagg(subkind,’;’)WITHIN GROUP(ORDER BY subkind) newkind FROM ( SELECT ‘水果’ kind,‘苹果’ subkind FROM dual UNION ALL SELECT ‘水果’,‘梨’ FROM dual UNION ALL SELECT ‘水果’,‘香蕉’ FROM dual UNION ALL SELECT ‘动物’,‘狗’ FROM dual UNION ALL SELECT ‘动物’,‘猫’ FROM dual ) a GROUP BY kind; |
select kind, string_agg(subkind,’;’ order by subkind) newkind from ( select ‘水果’ kind,‘苹果’ subkind union all select ‘水果’,‘梨’ union all select ‘水果’,‘香蕉’ union all select ‘动物’,‘狗’ union all select ‘动物’,‘猫’ ) a group by kind; |
递归查询 | start with…connect by | with recursive |
合并 | DROP TABLE example; CREATE TABLE example ( example_id NUMBER, example_name VARCHAR2(200) ); INSERT INTO example VALUES (1,‘样例1’); INSERT INTO example VALUES (1,‘样例1’); COMMIT; MERGE INTO example a USING ( SELECT 1 example_id, ‘MERGE后的样例1’ example_name FROM dual UNION SELECT 2 example_id, ‘MERGE后的样例2’ example_name FROM dual UNION SELECT 3 example_id, ‘MERGE后的样例3’ example_name FROM dual ) b ON (a.example_id = b.example_id) WHEN MATCHED THEN UPDATE SET a.example_name = b.example_name --限制当 example_id = 1 的时候才做更新 WHERE a.example_id = 1 WHEN NOT MATCHED THEN INSERT (a.example_id,a.example_name) VALUES (b.example_id,b.example_name); COMMIT; |
drop table example; create table example ( example_id numeric, example_name varchar(200) ); insert into example values (1,‘样例1’); insert into example values (2,‘样例2’); begin; with tmp_a as ( SELECT 1 example_id, ‘MERGE后的样例1’ example_name UNION SELECT 2 example_id, ‘MERGE后的样例2’ example_name UNION SELECT 3 example_id, ‘MERGE后的样例3’ example_name ) update example a set example_name = b.example_name from tmp_a b where a.example_id = b.example_id and a.example_id = 1; with tmp_a as ( SELECT 1 example_id, ‘MERGE后的样例1’ example_name UNION SELECT 2 example_id, ‘MERGE后的样例2’ example_name UNION SELECT 3 example_id, ‘MERGE后的样例3’ example_name ) insert into example select a.example_id,a.example_name from tmp_a a where not exists ( select 1 from example b where a.example_id = b.example_id ); commit; |
DCL
操作 | Oracle | GP |
---|---|---|
schema授权与回收 | 无 | grant usage,create on schema tool to tool; revoke usage,create on schema tool from tool; |
表授权与回收查询、插入、更新 | GRANT SELECT,INSERT,UPDATE ON test TO tool; REVOKE SELECT,INSERT,UPDATE ON test FROM tool; |
grant select,insert,update on table test to tool; revoke select,insert,update on table test from tool; |
表授权与回收所有用户访问 | GRANT SELECT ON test TO public; REVOKE SELECT ON test FROM public; |
grant select on table test to public; revoke select on table test from public; |
存储过程授权与回收 | GRANT EXECUTE,DEBUG ON delete_example TO tool; REVOKE EXECUTE,DEBUG ON delete_example FROM tool; |
grant execute on function delete_example() to tool; revoke execute on function delete_example() from tool; |
PL/SQL和PL/PGSQL
匿名程序块
数据库 | 定义 | 举例 |
---|---|---|
Oracle | DECLARE --可选 --variables,cursors,user-defined exceptions BEGIN --强制的(必须的) --一个或多个SQL语句 --一个或多个PL/SQL语句 EXCEPTION --可选 --当错误发生是要进行的处理 END; --强制的(必须的) / |
DECLARE var VARCHAR2(100) := ‘hello world!’; BEGIN dbms_output.put_line(var); END; / |
GP | do $$ declare --可选 --variables,cursors,user-defined exceptions begin --强制的(必须的 --一个或多个SQL语句 --一个或多个PL/PGSQL语句 exception --可选 --当错误发生是要进行的处理 end$$; --强制的(必须的) |
do $$ declare var varchar(100) := ‘hello world!’; begin raise notice ‘%’,var; end$$; |
替代变量
数据库 | 定义 | 举例 |
---|---|---|
Oracle(Sql plus) | define | define a = 1 SELECT &a FROM dual; SELECT &&a FROM dual; |
GP(Psql) | \set | \set a 1 select :a; |
字符串分隔符
数据库 | 定义 | 描述 | 举例 |
---|---|---|---|
Oracle | ‘’ | 单引号,字符串中有单引号,需加’转义 | SELECT ‘What’‘s your name?’ FROM dual; |
GP | ‘’ | 单引号,字符串中有单引号,需加’转义 | select ‘What’‘s your name?’; |
Oracle | q’ | q’可以自定义定界符,无需转义 | –通过q’定义||为定界符 SELECT q’|What’s your name?|’ FROM dual; –通过q’定义//为定界符 SELECT q’/What’s your name?/’ FROM dual; –通过q’定义{}为定界符 SELECT q’{What’s your name?}’ FROM dual; –通过q’定义[]为定界符 SELECT q’[What’s your name?]’ FROM dual; |
GP | $$ $$ | 无需转义,$$可以指定标签名 | select $$What’s your name?$$; select $sql$What’s your name?$sql$; |
%TYPE属性
- 使用 %type 属性按照之前已经声明过的变量或者数据库中表的列来声明一个变量;
- 当存储在一个变量中的值来自于数据库中的表时,最好使用 %type 声明这个变量;
- 当存储在一个变量中的值来自于数据库中的表时,最好使用 %type 声明这个变量;
数据库 | 举例 |
---|---|
Oracle | –建表 CREATE TABLE example ( example_id NUMBER, example_name VARCHAR2(200) ); –插入数据 INSERT INTO example VALUES (1,‘样例1’); INSERT INTO example VALUES (2,‘样例2’); COMMIT; –测试%TYPE DECLARE --用%TYPE属性声明p_example_id 是与example表中example_id相同的数据类型 p_example_id example.example_id%TYPE; --用%TYPE属性声明p_example_name 是与example表中example_name相同的数据类型 p_example_name example.example_name%TYPE; BEGIN --将从example表中读取的一行数据的两列分别写进p_example_id和p_example_name变量 SELECT * INTO p_example_id,p_example_name FROM example WHERE ROWNUM = 1; --在oracle输出区输出p_example_id的值 dbms_output.put_line(p_example_id); --在oracle输出区输出p_example_name的值 dbms_output.put_line(p_example_name); END; / |
GP | –建表 create table example ( example_id numeric, example_name VARCHAR(200) ) distributed by (example_id); –插入数据 insert into example values (1,‘样例1’); insert into example values (2,‘样例2’); –测试%TYPE do $$ declare --用%TYPE属性声明p_example_id 是与example表中example_id相同的数据类型 p_example_id example.example_id%type; --用%TYPE属性声明p_example_name 是与example表中example_name相同的数据类型 p_example_name example.example_name%type; begin --将从example表中读取的一行数据的两列分别写进p_example_id和p_example_name变量 select * into p_example_id,p_example_name from example limit 1; --在gp输出区输出p_example_id的值 raise notice ‘%’,p_example_id; --在gp输出区输出p_example_name的值 raise notice ‘%’,p_example_name; end$$; |
%ROWTYPE属性
利用%ROWTYPE属性声明一个能够存储一个表或视图中一整行数据的记录(变量);
数据库 | 举例 |
---|---|
Oracle | DECLARE --声明记录类型的变量 exp_record example%ROWTYPE; BEGIN --将从example表中获取到的一行数据放进已经声明的记录类型的变量exp_record中 SELECT example_id, example_name INTO exp_record FROM example WHERE ROWNUM = 1; --输出 dbms_output.put_line(exp_record.example_id); dbms_output.put_line(exp_record.example_name); END; / |
GP | do $$ declare --声明记录类型的变量 exp_record example%rowtype; begin --将从example表中获取到的一行数据放进已经声明的记录类型的变量exp_record中 select example_id, example_name into exp_record from example limit 1; --输出 raise notice ‘%’,exp_record.example_id; raise notice ‘%’,exp_record.example_name; end$$; |
IF语句
数据库 | 举例 |
---|---|
Oracle | DECLARE score NUMBER; BEGIN score := 100; IF score >= 90 AND score <= 100 THEN dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are very good!’); ELSIF score >= 70 AND score < 90 THEN dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are good!’); ELSIF score >= 60 AND score < 70 THEN dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are terrible!’); ELSE dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are terrible very much!’); END IF; score := 80; IF score >= 90 AND score <= 100 THEN dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are very good!’); ELSIF score >= 70 AND score < 90 THEN dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are good!’); ELSIF score >= 60 AND score < 70 THEN dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are terrible!’); ELSE dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are terrible very much!’); END IF; score := 65; IF score >= 90 AND score <= 100 THEN dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are very good!’); ELSIF score >= 70 AND score < 90 THEN dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are good!’); ELSIF score >= 60 AND score < 70 THEN dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are terrible!’); ELSE dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are terrible very much!’); END IF; score := 50; IF score >= 90 AND score <= 100 THEN dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are very good!’); ELSIF score >= 70 AND score < 90 THEN dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are good!’); ELSIF score >= 60 AND score < 70 THEN dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are terrible!’); ELSE dbms_output.put_line('Your score is ’ || to_char(score) || ‘, you are terrible very much!’); END IF; END; / |
GP | do $$ declare score numeric; begin score := 100; if score >= 90 and score <= 100 then raise notice ‘Your score is %, you are very good!’,score; elsif score >= 70 and score < 90 then raise notice ‘Your score is %, you are good!’,score; elsif score >= 60 and score < 70 then raise notice ‘Your score is %, you are terrible!’,score; else raise notice ‘Your score is %, you are terrible very much!’,score; end if; score := 80; if score >= 90 and score <= 100 then raise notice ‘Your score is %, you are very good!’,score; elsif score >= 70 and score < 90 then raise notice ‘Your score is %, you are good!’,score; elsif score >= 60 and score < 70 then raise notice ‘Your score is %, you are terrible!’,score; else raise notice ‘Your score is %, you are terrible very much!’,score; end if; score := 65; if score >= 90 and score <= 100 then raise notice ‘Your score is %, you are very good!’,score; elsif score >= 70 and score < 90 then raise notice ‘Your score is %, you are good!’,score; elsif score >= 60 and score < 70 then raise notice ‘Your score is %, you are terrible!’,score; else raise notice ‘Your score is %, you are terrible very much!’,score; end if; score := 50; if score >= 90 AND score <= 100 then raise notice ‘Your score is %, you are very good!’,score; elsif score >= 70 AND score < 90 then raise notice ‘Your score is %, you are good!’,score; elsif score >= 60 AND score < 70 then raise notice ‘Your score is %, you are terrible!’,score; else raise notice ‘Your score is %, you are terrible very much!’,score; end if; end$$; |