Here's the basic way to extract the JSON values in Postgres:
data2->'account_id' AS channel
So, your execute SQL should be something like this:
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,)
)
If you want to remove the account_id/id keys before inserting the rest of the JSON into the report_data field, then you can create a second "data2" variable (i.e. "data2_final" with the removed keys and also pass that as a parameter to your SQL. Let me know how it works for you.
Updated
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
I updated the extract to return the JSON values as text and then cast them as INTEGER.
Updated Update
I formatted your code below as I understood it with the changes I made noted below:
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()
Changes:
- removed the extra double-quotes at start and end of sql_cmd
- added a double-quote after "src" in the query
- moved the (data2,) tuple to the cur.execute() call
The way the execute() function works, is you pass it the SQL string you want to execute (i.e. sql_cmd) as the first parameter. The %s thingies in the string are placeholders for the parameterized values. As a second argument, you pass an array/tuple containing the parameter values (i.e. (data2,)).
Fingers crossed :)
Updated Updated Update
Here is the working code (slightly modified version from what you provided):
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()
Changes
- added sql_params variable to calldb() to pass along sql parameters
- added connection params line to connect to DB (not sure how you were
doing it in yours)
- converted data2 dictionary data type to JSON data type (that's related to why you were getting the previous "can't adapt dict" error)
- Suggestion: Not sure if you do this or not, but you should also close your DB cursor and connection when you're done with them
You can clean it up and modify as needed. Give it a try and let me know.