三、 Greenplum数据库的基本使用
1. 启动和停止
su gpadmin
gpstart -a ( -a的原因是不需要在手动输入yes)
gpstop -a
2. 查看数据库状态
psql -l
pgstate
3. 命令行连接访问数据库
在命令行界面也可以输入以下
\h:查看SQL命令的解释,比如\h select。
\?:查看psql命令列表。
\l:列出所有数据库。
\c [database_name]:连接其他数据库。
\d:列出当前数据库的所有表格。
\d [table_name]:列出某一张表格的结构。
\du:列出所有用户。
\e:打开文本编辑器。
\conninfo:列出当前数据库和连接的信息。
\d tblname 查看表结构,相当于desc tblname,show columns from tbname
\dt 列举表,相当于mysql的show tables
\di 查看索引
\df 查看函数
\copyright 显示 PostgreSQL 的使用和发行条款
\encoding [字元编码名称] 显示或设定用户端字元编码
\h [名称] SQL 命令语法上的说明,用 * 显示全部命令
\password [USERNAME] 、修改用户密码
\q 退出命令行界面
4 一些DML操作
# 创建新表
CREATE TABLE user_tbl(name VARCHAR(20), signup_date DATE);
# 插入数据
INSERT INTO user_tbl(name, signup_date) VALUES('张三', '2013-12-22');
# 选择记录
SELECT * FROM user_tbl;
# 更新数据
UPDATE user_tbl set name = '李四' WHERE name = '张三';
# 删除记录
DELETE FROM user_tbl WHERE name = '李四' ;
# 添加栏位
ALTER TABLE user_tbl ADD email VARCHAR(40);
# 更新结构
ALTER TABLE user_tbl ALTER COLUMN signup_date SET NOT NULL;
# 更名栏位
ALTER TABLE user_tbl RENAME COLUMN signup_date TO signup;
# 删除栏位
ALTER TABLE user_tbl DROP COLUMN email;
# 表格更名
ALTER TABLE user_tbl RENAME TO backup_tbl;
# 删除表格
DROP TABLE IF EXISTS backup_tbl;
创建数据库
createdb serviceDB(库名) -E utf-8
然后默认数据库
export GPDATABASE=serviceDB
进入命令界面
psql
psql -d servicedb -h node-01 -p 5432 -U gpadmin 会进入命令行页面
通过psql 指定指定的数据库 ,,机器的节点, 端口号, 用户名 可以使其他的机器登陆到greenplum数据库
比如在node-03上 通过上述的指令 进入大greenplum数据库
基本语法
1 获取基本语法介绍
可以使用 \h 查看GreenPlum支持的所有语法
在psql中使用\h command
2 create table
与其他数据库不同的地方:
- 在Greenplum中建表时需要指定表的分布键
- 如果表需要用某个字段分区,可以通过partition by将表建成分区表
- 可以使用like操作创建与like的表一样结构的表,功能类似 create table t1 as select * from t2 limit 0
- 可以使用inherits实现表的继承
CREATE [[GLOBAL|LOCAL] {TEMPORARY|TEMP}] TABLE table_name (
[
{
column_name data_type [DEFAULT default_expr]
[column_constraint [...]]
| table_constraint
| LIKE ohter_table [{INCLUDING|EXCLUDING} {DEFAULTS|CONSTRAINTS} ...]
}
[,...]
]...
)
[INHERITS (parent_table [,...])]
[WITH (storage_parameter=value [,...])
[ON COMMIT {PRESERVE ROWS|DELETE ROWS|DROP}]
[TABLESPACE tablespace]
[DISTRIBUTED BY (column,[...]) | DISTRIBUTED RANDOMLY]
[PARTITION BY partition_type (column)
[SUBPARTITION BY partition_type (column)]
[SUBPARTITION TEMPLATE (template_spec)]
[...]
(partition_spec)
|[SUBPARTITION BY partition_type(column)]
[...]
(partition_spec)
[(subpartition_spec
[(...)]
)]
]
Greenplum是一个分布式数据库,有两种数据分布策略:
1. Hash分布。指定一个活多个分布键,计算hash值,并且通过hash值路由到特定的Segment节点上,语法为Distributed by(…)。如果不指定分布键,默认将第一个字段作为分布键。
2. 随机分布,也叫平均分布。数据随机分散在每一个节点中,这样无论数据是什么内容,都可以平均分布在每个节点上,==但是在执行SQL的过程中,关联等操作都需要将数据重分布,性能较差。==语法为在表字段定义的后面加上Distributed randomly
采用随机分布策略的表默认将主键或唯一键作为分布键,因为每一个Segment都是一个单一的数据库,单个的数据库可以保证唯一性,多个数据库节点就无法保证全局的跨库唯一性,故只能按照唯一键分布,同一个值的数据都在一个节点上,以此来保证唯一性。
==如果指定的分布键与主键不一样,那么分布键会被更改为主键。==
使用like创建的表,只是表结构会与原表一模一样,表的一些特殊属性并不会一样,例如压缩、只增 appendonly等。如果不指定分布键,则默认分布键与原表相同。
3.SELECT
SELECT语句的基本语法跟其他数据库类似,也有自己的一些特性,例如分页采用offset加limit操作
SELECT可以不用指定From字句,如执行函数、进行一些简单的科学计算等。
如果不加order by字句,查询的结果中,数据的顺序是不能够保证的。
4 create table as 与 select into
create table as 与 select into 有一样的功能,都可以使表根据直接执行SELECT的结果创建出一个新的表,这个在临时分析数据的时候十分方便。例如,在创建一个表的时候如果默认不指定分布键,那么Greenplum根据执行SELECT得到的结果集来选择,不用再次分重分布数据的字段作为表的分布键。
也可以手动加入distributed关键字,指定分布键,这样数据就会根据指定分布键再建表。
select into的语法比create table as更简单,虽然功能一样,但是执行select into不能指定分布键,只能使用默认的分布键。
5.explain
explain用于查询一个表的执行计划。
testDB=# explain
select * from test1 x,test2 y where x.id=y.id;
6.insert/update/delete
insert
在执行insert语句的时候,注意分布键不要为空,否则分布键默认会变成null,数据都被保存在一个节点上,造成数据分布不均。
可以批量操作
testDB=#
insert into test001 values(100,'tom'),(101,'lily');
- 1
update
不能批量对分布键执行update,因为对分布键执行update需要将数据重分布,Greenplum暂时不支持这个功能。
delete
Greenplum 3.x版本中,如果delete操作涉及子查询,并且子查询的结果还会涉及数据重分布,这样的删除语句会报错。
对整张表执行Delete较慢,有此需求时建议使用truncate
7.truncate
与oracle一样,执行truncate直接删除表的物理文件,然后创建新的数据文件。truncate操作比delete操作在性能上有非常大的提升,当前如果有sql正在操作这张表,那么truncate操作会被锁住,知道表上面的所有锁被释放.
常用数据类型
Greenplum的数据类型基本与PostgreSQL的一样。
1.数值类型
类型名称 | 存储空间 | 描述 | 范围 |
smallint | 2字节 | 小范围整数 | -32 768~+32 767 |
integer | 4字节 | 常用的整数 | -2 147 483 648~+2 147 483 647 |
bigint | 8字节 | 大范围的整数 | -9 223 372 036 854 775 808~9 223 372 036 854 775 807 |
decimal | 变长 | 用户声明精度,精确 | 无限制 |
numeric | 变长 | 用户声明精度,精确 | 无限制 |
real | 4字节 | 变精度,不精确 | 6位十进制数字精度 |
double precision | 8字节 | 变精度,不精确 | 15位十进制数字精度 |
serial | 4字节 | 自增整数 | 1 - 2 147 483 647 |
bigserial | 8字节 | 大范围的自增整数 | 1 - 9 223 372 036 854 775 807 |
2.字符类型
类型名称 | 描述 |
character varying(n),varchar(n) | 变长,有长度限制 |
character(n),char(n) | 定长,不足补空白 |
text | 变长,无长度限制 |
3.时间类型
类型名称 | 存储空间 | 描述 | 最低值 | 最高值 | 时间精度 |
timestamp[(p)][without time zone] | 8字节 | 日期和时间 | 4713BC | 5874897AD | 1毫秒 |
timestamp[(p)] with time zone | 8字节 | 日期和时间,带时区 | 4713BC | 5874897AD | 1毫秒 |
interval[(p)] | 12字节 | 时间间隔 | -178 000 000年 | 178 000 000年 | 1毫秒 |
date | 4字节 | 只用于表示日期 | 4713BC | 5 874 897AD | 1天 |
time[(p)][without time zone] | 8字节 | 只用于表示一日内的时间 | 00:00:00 | 24:00:00 | 1毫秒 |
time[(p)] with time zone | 12字节 | 只用于表示一日内时间,带时区 | 00:00:00+1459 | 24:00:00-1459 | 1毫秒 |
常用函数
字符串函数
函数 | 返回类型 | 描述 | 例子 | 结果 |
string||string | text | 字符串连接 | ||
length(string) | int | string中字符的数目 | length(‘jose’) | 4 |
position(substring in string) | int | 指定的子字符串的位置 | position(‘om’in’Tomas’) | 3 |
substring(string[from int][for int]) | text | 抽取子字符串 | substring(‘Thomas’from 2 for 3) | hom |
trim([leading|trailing|both][characters]from string) | text | 从字符串string的开头/结尾/两边删除只包含characters中字符(默认是空白)的最长的字符串 | trim(both ‘x’ from ‘xTomxx’) | Tom |
lower(string) | text | 把字符串转化为小写 | ||
upper(string) | text | 把字符串转化为大写 | ||
overlay(string placing string from int [for int]) | text | 替换子字符串 | overlay(‘Txxxxas’ placing ‘hom’ from 2 for 4) | Thomas |
replace(string text,from text,to text) | text | 把字符串string中出现的所有子字符串from替换成子字符串to | replace(‘abcdefabcdef’,’cd,’XX’) | abXXefabXXef |
split_part(string text, delimiter text,filed int) | text | 根据delimiter分隔string返回生成的第field个子字符串(1开始) | split_part(‘abc|def|ghi’,’|’,2) | def |
时间函数
函数 | 返回类型 | 描述 | 例子 | 结果 |
age(timestamp,timestamp) | interval | 减去参数后的”符号化”结果 | age(timestamp’2001-04-10’,timestamp’1957-06-13) | 43 years 9 mons 27 das |
age(timestam) | interval | 从current_date减去参数中的日期 | age(timestam’1957-06-13) | - |
current_date | date | 当前的日期 | - | - |
current_time | time with time zone | 当日时间 | - | - |
current_timestamp | timestamp with time zone | 当前事务开始时的事件戳 | - | - |
date_part(text,timestamp) | double precision | 获取子域(等效于extract) | date_part(‘hour’,timestamp’2001-02-16 20:38:40) | 20 |
date_trunc(text,timestamp) | timestamp | 截断成指定的精度 | date_trunc(‘hour’,timestamp ‘2001-02-16 20:38:40’) | 2001/2/16 20:00 |
extract(field from timestamp) | double precision | 获取子域 | (同date_part) | (同date_part) |
now() | timestampe with time zone | 当前事务开始的时间戳 | - |
使用interval类型可以直接对事件类型进行计算,用来计算时间的加减
数值计算函数
函数 | 返回类型 | 描述 | 例子 | 结果 |
abs(x) | (与x相同) | 绝对值 | - | - |
ceil(dp或numeric)\ceiling | (与输入相同) | 不小于参数的最小整数 | - | - |
exp(dp或numeric) | (与输入相同) | 自然指数 | - | - |
ln(dp或numeric) | (与输入相同) | 自然对数 | - | - |
log(dp或numeric) | (与输入相同) | 以10 为底的对数 | - | - |
log(b numeric,x numeric) | numeric | 以b为底的对数 | - | - |
mod(y,x) | (与参数类型相同) | y/x的余数 | - | - |
pi() | dp | π | - | - |
power(a numeric,b numeric) | numeric | a的b次幂 | - | - |
radians(dp) | dp | 把角度转为弧度 | - | - |
random() | dp | 0~1之间的随机数 | ||
floor(dp或numeric) | (与输入相同) | 不大于参数的最大整数 | - | - |
round(v numeric,s int) | numeric | 圆整为s位小数 | round(42.4382,2) | 42.44 |
sign(dp或numeric) | (与输入相同) | 参数的符号(-1,0,+1) | sing(-8,4) | -1 |
sqrt(dp或numeric) | (与输入相同) | 平方根 | - | - |
cbrt(dp) | dp | 立方根 | - | - |
trunc(v numeric,s int) | numeric | 截断为s位小数 | - | - |
其他常用函数
序列号生成函数——generate_series
generate_series(x,y,t)
- 1
生成多行数据从x到另外y,步长为t,默认是1
字符串列转行——string_agg
string_agg(
str,symbol [
orderby
str
])
- 1
(按照某字段排序)将str列转行,以symbol分隔
字符串行转列——regexp_split_to_table
…
hash函数——md5,hashbpchar
md5的hash算法精度为128位,返回一个字符串
Hashbpchar的精度是32位,返回一个integer类型
分析函数
开窗函数
聚合函数返回各个分组的结果,开窗函数则为每一行返回结果。
rank()、row_number
grouping sets
如果需要对几个字段的组合进行group ,需要用到grouping sets功能
group sets语法 | 等价的普通SQL的语法 |
SELECT C1,C2,SUM(C3)FROM T GROUP BY GROUPING SETS((C1),(C2)) | SELECT C1,NULL AS C2,SUM(C3) FROM T GROUP BY T UNION ALL SELECT NULL AS C1,C2,SUM(C3) FROM T GROUP BY YEAR |
GROUP BY GROUPING SETS((C1,C2,…Cn)) | GROUP BY C1,C2,…,Cn |
GROUP BY ROLLUP(C1,C2,…,Cn-1,Cn) | GROUP BY GROUPING SETS((C1,C2,…CCn-1,Cn),(C1,C2,…,Cn-1)…,(C1,C2),(C1),()) |
GROUP BY CUBE(C1,C2,C3) | GROUP BY GROUPING SETS((C1,C2,C3),(C1,C2),(C1,C3),(C2,C3),(C1),(C2),(C3),()) |
分区表
Greenplum支持分区表。
可以使用时间分区、Every分区、list分区、
创建分区表
[PARTITION BY partition_type (column)
[SUBPARTITION BY partition_type (column)]
[SUBPARTITION TEMPLATE (template_spec)]
[...]
(partition_spec)
|[SUBPARTITION BY partition_type(column)]
[...]
(partition_spec)
[(subpartition_spec
[(...)]
)]
]
and partition_element is:
DEFAULT PARTITION name
| [PARTITION name] VALUES (list_value[,...])
| [PARTITION name]
START ([datatype] 'start_value') [INCLUSIVE|EXCLUSIVE]
[ END ([datatype] 'end_value') [INCLUSIVE|EXCLUSIVE]
[ EVERY ([datatype] [number|INTERVAL] 'interval_value')]
| [PARTITION name]
END ([DATATYPE] 'end_value') [INCLUSIVE|EXCLUSIVE]
[ EVERY ([datatype] [number|INTERVAL] 'interval_value')]
[ with (partition_storage_parameter=value [,...])]
[ TABLESPACE tablespace]
Tips
通过实验得到:向主表插入数据时,数据会被自动存放至相应的分区表。
也可以直接向分区子表插入符合条件的数据,
当向分区子表插入不符合条件的额数据时,会提示:
[Err] ERROR: Trying to insert row into wrong partition (seg1 hadoop3:40000 pid=6679)
DETAIL: Expected partition: test_partition_range_1_prt_p20111231, provided partition: test_partition_range_1_prt_p20111230
删除主表是会自动删除关联的分区表
Examples
按时间分区
create table public.test_partition_range(
id numeric,
name character varying(32),
dw_end_date date
)Distributed by (id)
PARTITION BY range(dw_end_date)
(
PARTITION p20111230 START ('2011-12-30'::date) END ('2011-12-31'::date),
PARTITION p20111231 START ('2011-12-31'::date) END ('2012-01-01'::date)
);
在各自的分区表中插入数据,总表中会有显示.删除总表后,分区表直接删除
使用Every分区
使用Every分区
create table test.test_partition_every(
id numeric,
name character varying(32),
dw_end_date date
) distributed by(id)
partition by range(dw_end_Date)
(
partition p201112 start('2011-12-1'::date) end ('2011-12-31'::date)
every ('1 days'::interval)
);
使用interval类型可以直接对事件类型进行计算,用来计算时间的加减
使用list分区
create table test.test_partition_list(
member_id numeric,
city character varying(32)
)distributed by (member_id)
partition by list(city)
(
partition guangzhou values('guangzhou'),
partition hangzhou values('hangzhou'),
default partition other_city
);
修改分区表
ALTER DEFAULT PARTITION
DROP DEFAULT PARTITION [IF EXISTS]
DROP PARTITION [IF EXISTS] {
partition_name
| FOR (RANK(number))
| FOR (value)
}
[CASCADE]
TRUNCATE DEFAULT PARTITION
TRUNCATE PARTITION {
partition_name
| FOR (RANK(number))
| FOR (value)
}
RENAME DEFAULT PARTITION TO new_partition_name
RENAME PARTITION {
partition_name
| FOR (RANK(number))
| FOR (value)
}
TO new_partition_name
ADD DEFAULT PARTITION NAME [(subpartition_spec)]
ADD PARTITION [name] partition_element
[(subpartition_spec)]
EXCHANGE PARTITION {
partition_name
| FOR (RANK(number))
| FOR (value)
} WITH TABLE TABLE_NAME
[WITH|WITHOUT VALIDATION]
EXCHANGE EFAULT PARTITION WITH TABLE TABLE_NAME
[WITH|WITHOUT VALIDATION]
SET SUBPARTITION TEMPLATE (subpartition_spec)
SPLIT DEFAULT PARTITION {
AT (list_value)
|START([datatype] range_value) [INCLUSIVE|EXCLUSIVE]
END ([datatype]) range_value) [INCLUSIVE|EXCLUSIVE]
}
[INTO (PARTITION new_partition_name,
PARTITION default_partition_name)]
SPLIT DPARTITION {
partition_name
| FOR (RANK(number))
| FOR (value)
} AT(value)
[INTO (PARTITION partition_name, PARTITION partition_name]
新增分区
alter table test.test_partition_every add partition p20120105_6
start ('2012-01-05'::date) END ('2012-01-07'::date);
drop/truncate分区
alter table test.test_partition_every drop partition p20120105_6;
alter table test.test_partition_every truncate partition p20120105_6;
拆分分区
alter table test.test_partition_every split partition p20120105_6
at(('2012-01-06'::date)) into (partition p20120105,partition p20120106);
交换分区
alter table test.test_partition_every exchange partition p20120102 with table test.test_on_partition;
外部表
Greenplum在数据加载上有一个明显的优势,就是支持数据并发加载,gpfdist就是并发加载的工具,在数据库中对应的就是外部表。
外部表就是一张表的数据是指向数据库之外的数据文件的。在Greenplum中,可以对一个外部表执行正常的DML操作,当读取数据的时候,数据库就从数据文件中加载数据。外部表支持在Segment上并发的告诉从gpfdist导入数据,由于是直接从Segment上导入数据,所以效率非常高。
创建外部表
CREATE [READABLE] EXTERNAL TABLE TABLE_NAME
(column_name data_type [,...] | LIKE other_table)
LOCATION ('file://seghost[:port]/path/file' [,...])
| ('gpfdist://filehost[:port]/file_pateern' [,...])
| ('gphdfs://hdfs_host[:port]/path/file')
FORMAT 'TEXT'
[( [HEADER]
[DELIMITER [AS] 'delimeter' | 'OFF']
[NULL [AS] 'null string']
[ESCAPTE [AS] 'escape'|'OFF']
[NEWLINE [AS] 'LF'|'CR'|'CRLF']
[FILL MISSING FIELDS] )]
| 'CSV'
[( [HEADER]
[QUOTE [AS] 'quote']
外部表需要指定gpfdist的IP和端口,详细目录地址。其中文件名支持通配符匹配。
可以编写多个gpfdist的地址,但是不能超过总的Segment数,否则会报错。在创建外部表的时候可以指定分隔符、err表、指定允许出错的数据条数,以及源文件的字符编码等。
外部表还支持本地文本文件的导入,效率较低,不建议使用。
外部表还支持HDFS的文件操作。
启动gpfdist及创建外部表
1.
首先在文件服务器上启动gpfdist服务,指定文件目录及端口
nohup
$GPHOME/bin/gpfdist
-d/home/admin
-p8888
>
/tmp/gpfdist
.log2>&1
&
nohup保证程序在Server端执行,当前会话关闭后,程序仍然正常运行
nohup是Unix/Linux中的一个命令,普通进程通过&符号放到后台运行,如果启动该程序的额控制台退出,则该进程终止。nohup命令启动程序,则在控制台退出后,进程仍然继续运行,起到守护进程额作用。
2.
准备好需要加载的数据文件,将其放在外部表文件及其的、home/admin/目录或该目录的子目录下,在Greenplum中创建对应的外部表
create external table test.test001_ext(
id integer,
name varchar(128)
)
location (
'gpfdist://10.20.151.11:8888/gpextdata/test001.txt'
)
format 'TEXT' (delimiter as E'|' null as '' escape 'OFF')
encoding 'gb18030' log errors into test.test001_err segment reject limit 10rows;
3.外部表查询及数据加载
testDB=#
select * from public.test001_ext
COPY命令
使用COPY命令可以实现将文件导出和导入,但是要通过Master,效率没有外部表高,但是在数据量比较小的情况下,COPY命令比外部表要方面很多。
COPY table [(colum [, ...]) ] FROM {'file'|STDIN}
[ [WITH]
[OIDS]
[HEADER]
[DELIMITER [AS] 'delimeter']
[NULL [AS] 'null string']
[ESCAPE [AS] 'escape' | 'OFF']
[NEWLINE [AS] 'LF'|'CR'|'CRLF']
[CSV [QUOTE [AS] 'quote']
[FORCE NOT NULL column [,...]]
[FILL MISSING FIELDS]
[ [LOG ERRORS INTO error_table] [KEEP]
SEGMENT REJECT LIMIT count [ROWS|PERCENT]]
COPY {table [(column [,...])] |(query) } TO {'file'|STDOUT}
[ [WITH]
[OIDS]
[HEADER]
[DELIMIETER [AS] 'delimeter']
[NULL [AS] 'null string']
[ESCAPE [AS] 'escape'|'OFF']
[CSV [QUOTE [AS] 'quote']
[FORCE QUOTE column [,...]]]
Greenplum 4.x中引入了可写外部表,在导出数据的时候可以用可写外部表并发导出,性能很好。但在Greeplum3.x版本中,导出数据只能通过COPY命令实现,数据在Master上汇总导出。
如果需要将数据远程导出到其他机器上,可以使用copy to stdout,远程执行psql连接到数据库上,然后通过管道将数据重定向成文件。
12 GP的存储过程
Greenplum支持SQL/PYTHON/PERL/C语言构建函数,以下着重介绍SQL 存储过程。
一个存储过程就是一个事务,包括对子过程的调用都在一个事务内
存储过程结构:
CREATE FUNCTION somefunc() RETURNS integer AS $$
DECLARE
quantity integer := 30;
BEGIN
RETURN ....;
END;
$$ LANGUAGE plpgsql;
赋值
给一个变量或行/记录赋值用下面方法:identifier := expression
例子:user_id := 20;
执行一个没有结果的查询: PERFORM query;
一个例子:
PERFORM create_mv('cs_session_page_requests_mv', my_query);
- 动态SQL
EXECUTE command-string [INTO [STRICT] target];
- SELECT INTO
Example:SELECT ID INTO VAR_ID FROM TABLEA
- 获取结果状态
GET DIAGNOSTICS variable = item [, ...];
一个例子:
·GET DIAGNOSTICS integer_var = ROW_COUNT;
- SQL返回变量
SQLERRM, SQLSTATE
- 控制结构
IF ... THEN ... ELSEIF ... THEN ... ELSE
LOOP, EXIT, CONTINUE, WHILE, FOR
- 从函数返回
有两个命令可以用来从函数中返回数据:RETURN 和 RETURN NEXT 。
Syntax:RETURN expression;
- 设置回调
EXEC SQL WHENEVER condition action;
condition 可以是下列之一:
SQLERROR,SQLWARNING,NOT FOUND
- 异常处理
EXCEPTION WHEN unique_violation
THEN
-- do nothing
END;
忽略错误:
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'an EXCEPTION is about to be raised';
RAISE EXCEPTION 'NUM:%, DETAILS:%', SQLSTATE, SQLERRM;
END;
- 错误和消息
RAISE level 'format' [, expression [, ...]];
Level:
Info:信息输入
Notice:信息提示
Exception:产生一个例外,将退出存储过程
Example: RAISE NOTICE 'Calling cs_create_job(%)', v_job_id;