0

我正在制作一个脚本,它应该为每个客户创建一个模式。我从一个定义了每个客户的模式应该是什么样子的数据库中获取所有元数据,然后创建它。一切都定义明确,表的类型、名称等。一个客户有许多表(fx、地址、客户、联系人、项目等),每个表都有相同的元数据。

我现在的程序:

  1. 从元数据数据库中获取我需要的一切。
  2. 在 for 循环中,创建一个表,然后更改表并添加每个元数据(这是为每个表完成的)。

现在我的脚本为每个客户运行大约一分钟,我认为这太慢了。它与我有一个循环有关,在那个循环中,我正在更改每个表。我认为我不应该改变(这可能不是那么聪明的方法),而是应该做如下的事情:请注意,这只是一个愚蠢但有效的例子:

for table in tables:
    con.execute("CREATE TABLE IF NOT EXISTS tester.%s (%s, %s);", (table, "last_seen   date", "valid_from    timestamp"))

但它给了我这个错误(它似乎将表名读取为字符串中的字符串..):

psycopg2.errors.SyntaxError:“'billing'”处或附近的语法错误

第 1 行:如果不存在则创建表 tester.'billing' ('last_seen da...

4

2 回答 2

0

考虑创建具有类型(即自动编号)ID 字段的表,然后通过结合使用for 标识符(模式名称、表名称、列名称、函数名称等)和数据的常规格式对serial所有其他字段使用 alter table SQL 语句中不是文字的类型。sql.Identifier

from psycopg2 import sql

# CREATE TABLE
query = """CREATE TABLE IF NOT EXISTS {shm}.{tbl} (ID serial)"""

cur.execute(sql.SQL(query).format(shm = sql.Identifier("tester"),
                                  tbl = sql.Identifier("table")))

# ALTER TABLE
items = [("last_seen", "date"), ("valid_from", "timestamp")]    
query = """ALTER TABLE {shm}.{tbl} ADD COLUMN {col} {typ}"""

for item in items:
    # KEEP IDENTIFIER PLACEHOLDERS
    final_query = query.format(shm="{shm}", tbl="{tbl}", col="{col}", typ=i[1])
    cur.execute(sql.SQL(final_query).format(shm = sql.Identifier("tester"), 
                                            tbl = sql.Identifier("table"),
                                            col = sql.Identifier(item[0]))

或者,str.join对 one 使用列表推导CREATE TABLE

query = """CREATE TABLE IF NOT EXISTS {shm}.{tbl} (
       "id" serial,
       {vals}
)"""

items = [("last_seen", "date"), ("valid_from", "timestamp")]  
val = ",\n       ".join(["{{}} {typ}".format(typ=i[1]) for i in items])

# KEEP IDENTIFIER PLACEHOLDERS
pre_query = query.format(shm="{shm}", tbl="{tbl}", vals=val)

final_query = sql.SQL(pre_query).format(*[sql.Identifier(i[0]) for i in items], 
                                        shm = sql.Identifier("tester"), 
                                        tbl = sql.Identifier("table"))    
cur.execute(final_query)

SQL (发送到数据库)

CREATE TABLE IF NOT EXISTS "tester"."table" (
       "id" serial,
       "last_seen" date,
       "valid_from" timestamp
)
于 2019-12-23T18:42:50.443 回答
0

但是,由于服务器往返次数过多,这变得很繁重。

您要创建多少列的表,这很慢?你可以通过 ssh 连接到离你的服务器更近的机器并在那里运行 python 吗?

我没有得到那个错误。相反,我得到一个 SQL 语法错误。值列表用于传送数据。但是 ALTER TABLE 不是关于数据,而是关于元数据。您不能在那里使用值列表。您需要双引号(或不带引号)而不是单引号中的列和类型的名称。名称和类型之间不能有逗号。而且你不能在每一对周围都有括号。而且每一对都需要用“ADD”来介绍,不能只用一次。您为这项工作使用了错误的工具。execute_batch 几乎是正确的工具,除了它将在标识符周围使用单引号而不是双引号。也许您可以向它添加一个标志,告诉它使用quote_ident。

不仅 execute_values 是错误的工作工具,而且我认为一般来说 python 可能也是如此。为什么不直接从.sql文件加载?

于 2019-12-23T14:36:37.787 回答