我正在将一个数据库从 postgres 转换为 mysql。
由于我找不到一个可以自己解决问题的工具,所以我将所有 postgres 序列转换为 mysql 中具有自动增量值的自动增量 ID。
那么,如何使用 SQL 查询列出Postgres DB(8.1版本)中的所有序列以及有关使用它的表、下一个值等的信息?
请注意,我不能information_schema.sequences
在 8.4 版本中使用该视图。
我正在将一个数据库从 postgres 转换为 mysql。
由于我找不到一个可以自己解决问题的工具,所以我将所有 postgres 序列转换为 mysql 中具有自动增量值的自动增量 ID。
那么,如何使用 SQL 查询列出Postgres DB(8.1版本)中的所有序列以及有关使用它的表、下一个值等的信息?
请注意,我不能information_schema.sequences
在 8.4 版本中使用该视图。
以下查询给出了所有序列的名称。
SELECT c.relname FROM pg_class c WHERE c.relkind = 'S';
通常一个序列被命名为${table}_id_seq
。简单的正则表达式模式匹配将为您提供表名。
要获取序列的最后一个值,请使用以下查询:
SELECT last_value FROM test_id_seq;
请注意,从 PostgreSQL 8.4 开始,您可以通过以下方式获取有关数据库中使用的序列的所有信息:
SELECT * FROM information_schema.sequences;
由于我使用的是更高版本的 PostgreSQL(9.1),并且一直在寻找相同的答案,所以为了后代和未来的搜索者,我添加了这个答案。
psql
使用标志启动-E
(“回显由\d
和其他反斜杠命令生成的实际查询”),然后输入\ds
命令以列出所有序列。您应该看到如下内容:
# \ds
********* QUERY **********
SELECT n.nspname as "Schema",
c.relname as "Name",
CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' WHEN 'I' THEN 'partitioned index' END as "Type",
pg_catalog.pg_get_userbyid(c.relowner) as "Owner"
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('S','')
AND n.nspname <> 'pg_catalog'
AND n.nspname <> 'information_schema'
AND n.nspname !~ '^pg_toast'
AND pg_catalog.pg_table_is_visible(c.oid)
ORDER BY 1,2;
**************************
List of relations
Schema | Name | Type | Owner
--------+--------------------------------+----------+-------
public | assignments_id_seq | sequence | root
public | framework_users_id_seq | sequence | root
public | lending_items_id_seq | sequence | root
public | proxy_borrower_requests_id_seq | sequence | root
public | roles_id_seq | sequence | root
public | stack_requests_id_seq | sequence | root
(6 rows)
要检查特定序列,您可以运行\d <sequence name>
:
# \d lending_items_id_seq
********* QUERY **********
(...about four queries...)
**************************
Sequence "public.lending_items_id_seq"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
--------+-------+---------+---------------------+-----------+---------+-------
bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1
Owned by: public.lending_items.id
一阵阵痛之后,我明白了。
实现这一目标的最佳方法是列出所有表格
select * from pg_tables where schemaname = '<schema_name>'
然后,对于每个表,列出所有具有属性的列
select * from information_schema.columns where table_name = '<table_name>'
然后,对于每一列,测试它是否有一个序列
select pg_get_serial_sequence('<table_name>', '<column_name>')
然后,获取有关此序列的信息
select * from <sequence_name>
序列信息:最大值
SELECT * FROM information_schema.sequences;
序列信息:最后一个值
SELECT * FROM <sequence_name>
自动生成的序列(例如为 SERIAL 列创建的序列)与父表之间的关系由序列所有者属性建模。
您可以使用ALTER SEQUENCE 命令的 OWNED BY 子句修改此关系
例如,由 foo_schema.foo_table 拥有的 ALTER SEQUENCE foo_id
将其设置为链接到表 foo_table
或 ALTER SEQUENCE foo_id 由 NONE 拥有
断开序列和任何表之间的连接
关于这种关系的信息存储在pg_depend 目录表中。
加入关系是 pg_depend.objid -> pg_class.oid WHERE relkind = 'S' - 将序列链接到加入记录,然后 pg_depend.refobjid -> pg_class.oid WHERE relkind = 'r' 之间的链接将记录加入拥有关系(表)
此查询返回数据库中的所有序列 -> 表依赖项。where 子句将其过滤为仅包含自动生成的关系,这将其限制为仅显示由 SERIAL 类型列创建的序列。
WITH fq_objects AS (SELECT c.oid,n.nspname || '.' ||c.relname AS fqname ,
c.relkind, c.relname AS relation
FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace ),
sequences AS (SELECT oid,fqname FROM fq_objects WHERE relkind = 'S'),
tables AS (SELECT oid, fqname FROM fq_objects WHERE relkind = 'r' )
SELECT
s.fqname AS sequence,
'->' as depends,
t.fqname AS table
FROM
pg_depend d JOIN sequences s ON s.oid = d.objid
JOIN tables t ON t.oid = d.refobjid
WHERE
d.deptype = 'a' ;
我知道这篇文章已经很老了,但我发现CMS的解决方案非常有用,因为我正在寻找一种将序列链接到表和列的自动化方法,并希望分享。pg_depend目录表的使用是关键。我将所做的事情扩展到:
WITH fq_objects AS (SELECT c.oid,n.nspname || '.' ||c.relname AS fqname ,
c.relkind, c.relname AS relation
FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace ),
sequences AS (SELECT oid,fqname FROM fq_objects WHERE relkind = 'S'),
tables AS (SELECT oid, fqname FROM fq_objects WHERE relkind = 'r' )
SELECT
s.fqname AS sequence,
'->' as depends,
t.fqname AS table,
a.attname AS column
FROM
pg_depend d JOIN sequences s ON s.oid = d.objid
JOIN tables t ON t.oid = d.refobjid
JOIN pg_attribute a ON a.attrelid = d.refobjid and a.attnum = d.refobjsubid
WHERE
d.deptype = 'a' ;
此版本将列添加到返回的字段列表中。有了表名和列名,调用pg_set_serial_sequence可以很容易地确保数据库中的所有序列都设置正确。例如:
CREATE OR REPLACE FUNCTION public.reset_sequence(tablename text, columnname text)
RETURNS void
LANGUAGE plpgsql
AS $function$
DECLARE
_sql VARCHAR := '';
BEGIN
_sql := $$SELECT setval( pg_get_serial_sequence('$$ || tablename || $$', '$$ || columnname || $$'), (SELECT COALESCE(MAX($$ || columnname || $$),1) FROM $$ || tablename || $$), true)$$;
EXECUTE _sql;
END;
$function$;
希望这有助于重置序列的人!
我知道问题是关于 postgresql 版本 8,但我在这里为想要在版本 10 和更高版本中获取序列的人写了这个简单的方法
您可以使用以下查询
select * from pg_sequences
获取所有序列:
select * from pg_sequences;
PSQL:
\ds
\ds+
\ds *actor*
\ds *actor*
将获取序列名称包含演员字符的所有序列。
此语句列出与每个序列关联的表和列:
代码:
SELECT t.relname as related_table,
a.attname as related_column,
s.relname as sequence_name
FROM pg_class s
JOIN pg_depend d ON d.objid = s.oid
JOIN pg_class t ON d.objid = s.oid AND d.refobjid = t.oid
JOIN pg_attribute a ON (d.refobjid, d.refobjsubid) = (a.attrelid, a.attnum)
JOIN pg_namespace n ON n.oid = s.relnamespace
WHERE s.relkind = 'S'
AND n.nspname = 'public'
更多看这里链接回答
select sequence_name, (xpath('/row/last_value/text()', xml_count))[1]::text::int as last_value
from (
select sequence_schema,
sequence_name,
query_to_xml(format('select last_value from %I.%I', sequence_schema, sequence_name), false, true, '') as xml_count
from information_schema.sequences
where sequence_schema = 'public'
) new_table order by last_value desc;
部分测试,但看起来大部分是完整的。
select *
from (select n.nspname,c.relname,
(select substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
from pg_catalog.pg_attrdef d
where d.adrelid=a.attrelid
and d.adnum=a.attnum
and a.atthasdef) as def
from pg_class c, pg_attribute a, pg_namespace n
where c.relkind='r'
and c.oid=a.attrelid
and n.oid=c.relnamespace
and a.atthasdef
and a.atttypid=20) x
where x.def ~ '^nextval'
order by nspname,relname;
信用到期的信用......它部分是从具有序列的已知表上的 \d 记录的 SQL 逆向工程的。我敢肯定它也可以更清洁,但是嘿,性能不是问题。
有点黑客,但试试这个:
select 'select ''' || relname || ''' as sequence, last_value from ' || relname || ' union'
FROM pg_catalog.pg_class c
WHERE c.relkind IN ('S','');
删除最后一个 UNION 并执行结果
对上一个答案的改进:
select string_agg('select sequence_name, last_value from ' || relname, chr(13) || 'union' || chr(13) order by relname)
from pg_class where relkind ='S'
这是另一个在序列名称旁边具有架构名称的
select nspname,relname from pg_class c join pg_namespace n on c.relnamespace=n.oid where relkind = 'S' order by nspname
通过解析 DEFAULT 子句获取每个表的每一列的序列。此方法提供有关链接到哪些列序列的信息,并且不使用某些序列可能不存在的依赖关系。甚至pg_get_serial_sequence(sch.nspname||'.'||tbl.relname, col.attname)
函数都没有为我找到所有序列!
解决方案:
SELECT
seq_sch.nspname AS sequence_schema
, seq.relname AS sequence_name
, seq_use."schema" AS used_in_schema
, seq_use."table" AS used_in_table
, seq_use."column" AS used_in_column
FROM pg_class seq
INNER JOIN pg_namespace seq_sch ON seq_sch.oid = seq.relnamespace
LEFT JOIN (
SELECT
sch.nspname AS "schema"
, tbl.relname AS "table"
, col.attname AS "column"
, regexp_split_to_array(
TRIM(LEADING 'nextval(''' FROM
TRIM(TRAILING '''::regclass)' FROM
pg_get_expr(def.adbin, tbl.oid, TRUE)
)
)
, '\.'
) AS column_sequence
FROM pg_class tbl --the table
INNER JOIN pg_namespace sch ON sch.oid = tbl.relnamespace
--schema
INNER JOIN pg_attribute col ON col.attrelid = tbl.oid
--columns
INNER JOIN pg_attrdef def ON (def.adrelid = tbl.oid AND def.adnum = col.attnum) --default values for columns
WHERE tbl.relkind = 'r' --regular relations (tables) only
AND col.attnum > 0 --regular columns only
AND def.adsrc LIKE 'nextval(%)' --sequences only
) seq_use ON (seq_use.column_sequence [1] = seq_sch.nspname AND seq_use.column_sequence [2] = seq.relname)
WHERE seq.relkind = 'S' --sequences only
ORDER BY sequence_schema, sequence_name;
注意1个序列可以在多个表中使用,所以这里可以多行列出。
此函数显示每个序列的 last_value。
它输出一个 2 列的表,上面写着序列名称加上它最后生成的值。
drop function if exists public.show_sequence_stats();
CREATE OR REPLACE FUNCTION public.show_sequence_stats()
RETURNS TABLE(tablename text, last_value bigint)
LANGUAGE 'plpgsql'
COST 100
VOLATILE
ROWS 1000
AS $BODY$
declare r refcursor; rec record; dynamic_query varchar;
BEGIN
dynamic_query='select tablename,last_value from (';
open r for execute 'select nspname,relname from pg_class c join pg_namespace n on c.relnamespace=n.oid where relkind = ''S'' order by nspname';
fetch next from r into rec;
while found
loop
dynamic_query=dynamic_query || 'select '''|| rec.nspname || '.' || rec.relname ||''' "tablename",last_value from ' || rec.nspname || '.' || rec.relname || ' union all ';
fetch next from r into rec;
end loop;
close r;
dynamic_query=rtrim(dynamic_query,'union all') || ') x order by last_value desc;';
return query execute dynamic_query;
END;
$BODY$;
select * from show_sequence_stats();
谢谢你的帮助。
这是更新数据库的每个序列的 pl/pgsql 函数。
---------------------------------------------------------------------------------------------------------
--- Nom : reset_sequence
--- Description : Générique - met à jour les séquences au max de l'identifiant
---------------------------------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION reset_sequence() RETURNS void AS
$BODY$
DECLARE _sql VARCHAR := '';
DECLARE result threecol%rowtype;
BEGIN
FOR result IN
WITH fq_objects AS (SELECT c.oid,n.nspname || '.' ||c.relname AS fqname ,c.relkind, c.relname AS relation FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace ),
sequences AS (SELECT oid,fqname FROM fq_objects WHERE relkind = 'S'),
tables AS (SELECT oid, fqname FROM fq_objects WHERE relkind = 'r' )
SELECT
s.fqname AS sequence,
t.fqname AS table,
a.attname AS column
FROM
pg_depend d JOIN sequences s ON s.oid = d.objid
JOIN tables t ON t.oid = d.refobjid
JOIN pg_attribute a ON a.attrelid = d.refobjid and a.attnum = d.refobjsubid
WHERE
d.deptype = 'a'
LOOP
EXECUTE 'SELECT setval('''||result.col1||''', COALESCE((SELECT MAX('||result.col3||')+1 FROM '||result.col2||'), 1), false);';
END LOOP;
END;$BODY$ LANGUAGE plpgsql;
SELECT * FROM reset_sequence();
假设exec()
在这篇文章https://stackoverflow.com/a/46721603/653539中声明的函数,可以使用单个查询获取序列及其最后的值:
select s.sequence_schema, s.sequence_name,
(select * from exec('select last_value from ' || s.sequence_schema || '.' || s.sequence_name) as e(lv bigint)) last_value
from information_schema.sequences s
这是一个示例,如何使用psql
它们获取所有序列的列表last_value
:
psql -U <username> -d <database> -t -c "SELECT 'SELECT ''' || c.relname || ''' as sequence_name, last_value FROM ' || c.relname || ';' FROM pg_class c WHERE (c.relkind = 'S')" | psql -U <username> -d <database> -t