不使用pg_dump从PostgreSQL DB中提取数据

时间:2010-05-05 05:17:54

标签: python sql xml postgresql

有一个PostgreSQL数据库,我只有限制访问权限(例如,我不能使用pg_dump)。我试图通过从数据库导出某些表来创建本地“镜像”。我没有从psql中将表转储为SQL所需的权限。现在,我只有一个Python脚本遍历我的table_names,选择所有字段,然后将它们导出为CSV:

for table_name, file_name in zip(table_names, file_names):
    cmd = """echo "\\\copy (select * from %s)" to stdout WITH CSV HEADER | psql -d remote_db | gzip > ./%s/%s.gz"""%(table_name,dir_name,file_name)
    os.system(cmd)

我想尽可能不使用CSV,因为我丢失了字段类型并且编码可能搞砸了。第一个最好的可能是使用\ copy获取表的生成SQL代码的某种方式。接下来最好的是XML,理想情况下可以通过某种方式保留字段类型。如果这不起作用,我认为最终选项可能是两个查询 - 一个用于获取字段数据类型,另一个用于获取实际数据。

非常感谢任何想法或建议 - 谢谢!

3 个答案:

答案 0 :(得分:3)

让我感到困惑的是“我没有将表格作为SQL从psql中转储所需的权限。” pg_dump独立运行,在psql之外(两者都是客户端)如果您有权连接到数据库并选择一个表,我猜您也可以使用pg_dump -t <table>转储它。我错过了什么吗?

答案 1 :(得分:2)

如果您使用psycopg2,则可以使用cursor.description检查列名称,并使用获取的数据类型将其转换为所需的字符串,如数据为可接受的格式。

此代码创建INSERT语句,您不仅可以使用PostgreSQL,还可以使用其他数据库(那么您可能需要更改日期格式):

cursor.execute("SELECT * FROM %s" % (table_name))
column_names = []
columns_descr = cursor.description
for c in columns_descr:
    column_names.append(c[0])
insert_prefix = 'insert into %s (%s) values ' % (table_name, ', '.join(column_names))
rows = cursor.fetchall()
for row in rows:
    row_data = []
    for rd in row:
        if rd is None:
            row_data.append('NULL')
        elif isinstance(rd, datetime.datetime):
            row_data.append("'%s'" % (rd.strftime('%Y-%m-%d %H:%M:%S') ))
        else:
            row_data.append(repr(rd))
    print('%s (%s);' % (insert_prefix, ', '.join(row_data)))

在psycopg2中甚至支持COPY。请看their docs

上与COPY相关的方法

如果您更喜欢使用元数据,那么您可以使用我的食谱:Dump PostgreSQL db schema to text。它基于Lorenzo Alberton的Extracting META information from PostgreSQL

答案 2 :(得分:1)

您可以使用这些查询(通过使用“psql --echo-hidden”和“\ d”获取)来获取基本元数据:

-- GET OID
SET oid FROM pg_class WHERE relname = <YOUR_TABLE_NAME>

-- GET METADATA
SELECT a.attname,
  pg_catalog.format_type(a.atttypid, a.atttypmod),
  (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),
   a.attnotnull, a.attnum
FROM pg_catalog.pg_attribute a
WHERE a.attrelid = <YOUR_TABLES_OID_FROM_PG_CLASS> AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum;

这将为您提供行中的名称,数据类型,默认值,空标志和字段顺序。要获得实际数据,最好的选择仍然是CSV - 内置COPY表TO STDOUT WITH CSV HEADER非常强大。但是如果您担心编码,请确保在转储CSV数据之前获取server_encoding和client_encoding的值。结合上述查询中的元数据应该提供足够的信息来正确解释CSV转储。