将JSON插入Postgres 9.5

时间:2017-12-10 23:52:45

标签: python sql postgresql

Python 3.6 中,我有一个变量' data2 ',其中包含 JSON ,如下所示:

{
    'id': 4573457, 'account_id': 456, 'address': '15 Millers Rd, WA', 
    'category_id': 4565, 'description': None, 'is_anonymous': False, 
    'iso_created_at': '2017-11-21T14:08:54+11:00', 
    'location': {
        'latitude': -56.564848493, 'longitude': 345.5948493}, 
    'report_state_id': 45655, 'report_state_name': 'ALL PICKED', 
    'title': 'South', 'user_id': 44555, 'user_short_name': 'Todd G.', 
    'users_alerted_count': 0, 'users_opened_count': 6, 'shape_id': 56
}

我想写一个insert语句将这些数据插入到我已在 Postgres 9.5 中创建的表中,该表有3列 - channel,report_id和report_data -

我想将来自JSON的'account_id'插入到频道列中,将'id'插入到report_id列中,将其余的JSON全部插入到report_data列中。

有人可以告诉我如何做到这一点吗?

3 个答案:

答案 0 :(得分:3)

以下是在Postgres中提取JSON值的基本方法:

  data2->'account_id' AS channel

所以,你的执行SQL应该是这样的:

cursor.execute("
    INSERT INTO MyTable (channel, report_id, report_data)
    SELECT 
      src.MyJSON->'account_id',
      src.MyJSON->'id',
      src.MyJSON
    FROM (
      SELECT %s AS MyJSON
    ) src
  ",
  (data2,)
)

如果要在将其余的JSON插入report_data字段之前删除account_id / id键,则可以创建第二个“data2”变量(即带有已删除键的“data2_final”,并将其作为SQL的参数。请告诉我它是如何工作的。

<强>更新

CREATE TABLE Mytable (
  channel INTEGER, 
  report_id INTEGER, 
  report_data JSONB
);

cursor.execute("
    INSERT INTO MyTable (channel, report_id, report_data)
    SELECT 
      CAST(src.MyJSON->>'account_id' AS INTEGER),
      CAST(src.MyJSON->>'id' AS INTEGER),
      src.MyJSON
    FROM (
      SELECT CAST(%s AS JSONB) AS MyJSON
    ) src
  ",
  (data2,)
)

http://www.sqlfiddle.com/#!17/fb3af/1

我更新了提取,将JSON值作为文本返回,然后将它们转换为INTEGER。

更新更新 我将下面的代码格式化了,因为我理解了下面所做的更改:

def calldb( db, sql_cmd): 
    try: 
        cur = db.cursor() 
        cur.execute(sql_cmd, (data2,)) 
        return 
    except Exception as e: 
        print ('Error ', e ) 
        raise 

sql_cmd=" INSERT INTO MyTable (channel, report_id, report_data) SELECT CAST(src.MyJSON->>'account_id' AS INTEGER), CAST(src.MyJSON->>'id' AS INTEGER), src.MyJSON FROM ( SELECT CAST(%s AS JSONB) AS MyJSON ) src" 
calldb(conn, sql_cmd) 
conn.commit()

更改

  • 删除了sql_cmd
  • 开头和结尾的额外双引号
  • 在查询
  • 中的“src”后添加了双引号
  • 将(data2,)元组移动到cur.execute()调用

execute()函数的工作方式是,将要执行的SQL字符串(即sql_cmd)作为第一个参数传递给它。字符串中的%s内容是参数化值的占位符。作为第二个参数,您传递包含参数值的数组/元组(即(data2,))。

手指交叉:)

更新了更新的更新
这是工作代码(稍微修改后的版本):

import psycopg2
import json

def calldb(db, sql_cmd, sql_params): 
    try: 
        cur = db.cursor()
        cur.execute(sql_cmd, sql_params)
        return
    except Exception as e: 
        print ('Error ', e ) 
        raise 

params = {
  "host":"DB_HOSTNAME",
  "database":"DB_NAME",
  "user":"USERNAME",
  "password":"PASSWORD"
}

conn = psycopg2.connect(**params)

# Prepare SQL
sql_cmd = "INSERT INTO MyTable (channel, report_id, report_data) SELECT CAST(src.MyJSON->>'account_id' AS INTEGER), CAST(src.MyJSON->>'id' AS INTEGER), src.MyJSON FROM ( SELECT CAST(%s AS JSONB) AS MyJSON ) src" 

# Convert dictionary to native JSON data type
data2 = {"id": 4573457, "account_id": 456, "address": "15 Millers Rd, WA"}
data2_json = json.dumps(data2)

sql_params = (data2_json,)

# Execute SQL
calldb(conn, sql_cmd, sql_params) 
conn.commit()

更改

  • 将sql_params变量添加到calldb()以传递sql参数
  • 添加了连接params线以连接到DB(不确定你是怎么回事 在你的身上做到这一点)
  • 将data2字典数据类型转换为JSON数据类型(这与您之前获取“无法调整dict”错误的原因有关)
  • 建议:不确定是否这样做,但是当你完成它们时你也应该关闭你的数据库光标和连接

您可以清理它并根据需要进行修改。试一试,让我知道。

答案 1 :(得分:1)

上面的答案有些复杂。

在psycopg2 office document中,有一个类类型调用psycopg2.extras.Json,它是一个ISQLQuote包装器,用于使Python对象适应json数据类型。

import psycopg2
import logging
from psycopg2.extras import Json

conn = psycopg2.connect(dbname="  ", 
                        user="  ",
                        password="  ", 
                        host="127.0.0.1", 
                        port="5432")
data2 = {
    'id': 4573457, 'account_id': 456, 'address': '15 Millers Rd, WA', 
    'category_id': 4565, 'description': None, 'is_anonymous': False, 
    'iso_created_at': '2017-11-21T14:08:54+11:00', 
    'location': {
        'latitude': -56.564848493, 'longitude': 345.5948493}, 
    'report_state_id': 45655, 'report_state_name': 'ALL PICKED', 
    'title': 'South', 'user_id': 44555, 'user_short_name': 'Todd G.', 
    'users_alerted_count': 0, 'users_opened_count': 6, 'shape_id': 56
}

item = {
    'channel': data2['account_id'],
    'report_id': data2['id'],
    'report_data': Json(dict([(k, v) for k, v in data2.items() if k not in ['account_id', 'id']]))
}



def sql_insert(tableName, data_dict):
    '''
        INSERT INTO onetable (channel,  report_id,  report_data)
        VALUES (%(channel)s, %(report_id)s, %(report_data)s );
    '''
    sql = '''
        INSERT INTO %s (%s)
        VALUES (%%(%s)s );
        '''   % (tableName, ',  '.join(data_dict),  ')s, %('.join(data_dict))
    return sql

tableName = 'onetable'
sql = sql_insert(tableName, item)
try:
    with conn.cursor() as cur:
        cur.execute(sql, item)
    conn.commit()
except Exception as e:
    logging.debug(e)
    conn.rollback()
finally:
    conn.close()

答案 2 :(得分:0)

您可以使用jsonb数据类型进行插入。 请参阅下面的链接。 https://www.compose.com/articles/faster-operations-with-the-jsonb-data-type-in-postgresql/