【问题标题】:ON CONFLICT DO UPDATE syntax and EXCLUDED error on cursor.executemanyON CONFLICT DO UPDATE 语法和 cursor.executemany 上的 EXCLUDED 错误
【发布时间】:2021-03-19 03:37:13
【问题描述】:

我在下面有一个简化的 postgres(版本 13)表,其中包含在 python 中使用 psycopg2 生成的更新行。 我的问题是当我更新行中的价格字段时,由于出现以下 ON CONFLICT DO UPDATE 错误,我无法完成更新。如果我不使用 ON CONFLICT DO UPDATE ,我可以更新图表,但我想要 ON CONFLICT DO UPDATE 因为它消除了重复的行。

使用 ON CONFLICT DO UPDATE ,我只需要更新字段“price”和“last_updated”,但仅当行匹配“id,item,original_price_date”时才更新

我在 CONFLICT DO UPDATE 上遇到以下错误:

错误:“=”处或附近的语法错误

# update the prices within the existing data
df = pd.DataFrame(np.array([['5/3/2010', 'rock', 15],
                            ['4/15/2010', 'paper', 11],
                            ['2/3/2015', 'scissor', 13]]),
                             columns = ['original_price_date', 'item', 'price'])
tuples_for_dB = [tuple(x) for x in df.to_numpy()]
sql_script = '''INSERT INTO ''' + TABLE_ + ''' (
  original_price_date, item, price, created_date, last_updated) 
  VALUES (%s, %s, %s, transaction_timestamp(), transaction_timestamp())
  ON CONFLICT (id, item, original_price_date)
  DO UPDATE SET (price, last_updated = EXCLUDED.price, EXCLUDED.transaction_timestamp());'''

错误:关系“price_data”不存在

sql_script = '''INSERT INTO ''' + TABLE_ + ''' (
  original_price_date, item, price, created_date, last_updated) 
  VALUES (%s, %s, %s, transaction_timestamp(), transaction_timestamp())
  ON CONFLICT (id, item, original_price_date)
  DO UPDATE SET (price, last_updated) = (EXCLUDED.price, EXCLUDED.transaction_timestamp());'''

我原创的数据:

   # postGRESQL connection details
DATABASE_INITIAL_ = 'postgres'
DATABASE_ = 'data'
TABLE_ = 'price_data'
USER_ = 'postgres'
SERVERNAME_ = 'localhost'
PASSWORD_ = password_
HOST_ = '127.0.0.1'
PORT_ = '5432'

#establishing the connection
conn = psycopg2.connect(database = DATABASE_,
                        user = USER_,
                        password = PASSWORD_,
                        host = HOST_,
                        port = PORT_);
conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT);
conn.autocommit = True

# Creating a cursor object using the cursor() method
cursor = conn.cursor()

sql = "SELECT 1 FROM pg_catalog.pg_database WHERE datname = " + "'" + DATABASE_ + "'"
cursor.execute(sql)

# If dB does not exist create the dB
exists = cursor.fetchone()
print(exists)
if not exists:
    print('does not exist')
    #Preparing query to create a database
    sql = '''CREATE database '''+DATABASE_;

    #Creating a database
    cursor.execute(sql)

# Creating the table
sql = '''CREATE TABLE IF NOT EXISTS ''' + TABLE_ + ''' (
  id SERIAL PRIMARY KEY,
  original_price_date DATE NOT NULL,
  item TEXT NOT NULL,
  price NUMERIC NULL DEFAULT NULL,
  created_date TIMESTAMPTZ NULL DEFAULT TRANSACTION_TIMESTAMP(),
  last_updated TIMESTAMPTZ NULL DEFAULT TRANSACTION_TIMESTAMP());'''
cursor.execute(sql)

# update the table with data
df = pd.DataFrame(np.array([['5/3/2010', 'rock', 0.9],
                            ['4/15/2010', 'paper', 6.5],
                            ['2/3/2015', 'scissor', 3.9],
                            ['3/23/2017', 'ball', 1.1],
                            ['4/7/2013', 'tire', 5.4]]),
                             columns = ['original_price_date', 'item', 'price'])
tuples_for_dB = [tuple(x) for x in df.to_numpy()]
sql_script = '''INSERT INTO ''' + TABLE_ + ''' (
  original_price_date, item, price, created_date, last_updated) 
  VALUES (%s, %s, %s, transaction_timestamp(), transaction_timestamp());'''

try:
    cursor.executemany(sql_script, tuples_for_dB);                
    success = True
except psycopg2.Error as e:
    error = e.pgcode
    print(f'Error : {e.args[0]}')
    success = False
if success:
    print(f'\nData inserted successfully........')      
    print(f'Table INSERT sql commit comment :\n"{sql_script}"\n')
elif success == False:
    print(f'\nData NOT inserted successfully XXXXXX')      
            
# Preparing query to drop a table
sql = '''DROP TABLE IF EXISTS ''' + TABLE_ + ";"
# Creating the table
cursor.execute(sql)

conn.close()

【问题讨论】:

  • 第一个片段中的问题是括号。它必须是(field,field,field) = (value,value,value)。您在第二个 sn-p 中解决了这个问题。至于price_data does not exist error,在发生这种情况的文件中,您是否连接到正确的数据库?
  • 我没有看到你在创建脚本的任何地方调用conn.commt()。如果在psql命令行工具中打开数据库,看到表了吗?
  • 是的。我看到带有 cmd 行的表,所以它确实在数据库中。最后运行我的脚本是一个 DROP TABLE cmd。如果我将此表注释掉,初始数据将保留在 postgres 中。抱歉,我添加了它,因为我不得不一遍又一遍地重新创建表格。根据提交问题,我添加了 conn.autocommit = True。
  • 好的,但是您向我们展示的失败代码不是来自创建脚本,对吧?如果您在创建脚本的末尾删除了表,那么当您执行数据框时它就不会存在。对吗?
  • 这个表对于这个问题非常简化。 ON CONFLICT DO UPDATE 错误是由我的百万行数据库引起的。同样的错误在这里也适用。我仍然收到语法错误错误:“=”处或附近的语法错误。我可以编辑我的原始帖子以删除 DROP TABLE。

标签: python postgresql psycopg2


【解决方案1】:

我在创建表的位置添加了一个约束行 (CONSTRAINT com UNIQUE (original_price_date,item))。

sql = '''CREATE TABLE IF NOT EXISTS ''' + TABLE_ + ''' (
  id SERIAL PRIMARY KEY,
  original_price_date DATE NOT NULL,
  item TEXT NOT NULL,
  price NUMERIC NULL DEFAULT NULL,
  created_date TIMESTAMPTZ NULL DEFAULT TRANSACTION_TIMESTAMP(),
  last_updated TIMESTAMPTZ NULL DEFAULT TRANSACTION_TIMESTAMP(),
  CONSTRAINT com UNIQUE (original_price_date,item));'''

然后我可以通过以下语句插入数据而不创建 (original_price_date,item) 的重复行。

 sql = '''INSERT INTO ''' + TABLE_ + '''(original_price_date, item, price) 
                VALUES (%s, %s, %s)
                ON CONFLICT (original_price_date, item) 
                DO UPDATE 
                    SET (price, last_updated)  = (EXCLUDED.price,TRANSACTION_TIMESTAMP());'''

【讨论】:

    猜你喜欢
    • 2022-06-15
    • 2018-08-02
    • 1970-01-01
    • 2016-05-11
    • 2017-02-07
    • 2021-02-16
    • 1970-01-01
    • 1970-01-01
    • 2016-04-26
    相关资源
    最近更新 更多