【发布时间】:2022-01-12 18:11:00
【问题描述】:
我想将一个 json 数组保存到 azure sql server 中,但出现此错误:
\serverCalls\sqlManager.py",第 95 行,在 populateNewsLatest 诅咒.执行(f“”“ pyodbc.Error: ('07002', '[07002] [Microsoft][ODBC Driver 17 for SQL Server]COUNT 字段不正确或语法错误 (0) (SQLExecDirectW)')
这是我要保存的 json:
[
{
"source": {
"id": null,
"name": "Slashdot.org"
},
"author": "msmash",
"title": "World's Biggest Crypto Fortune Began With a Friendly Poker Game",
"description": "An anonymous reader shares a report: The Abu Dhabi Grand Prix draws princes, movie stars and world-famous athletes every year to party on Yas Island, the entertainment hub about 30 minutes from the center of downtown. Mingling among them last month was a figu\u2026",
"url": "https://slashdot.org/story/22/01/10/143214/worlds-biggest-crypto-fortune-began-with-a-friendly-poker-game",
"urlToImage": "https://a.fsdn.com/sd/topics/bitcoin_64.png",
"publishedAt": "2022-01-10T14:03:00Z",
"content": "The Abu Dhabi Grand Prix draws princes, movie stars and world-famous athletes every year to party on Yas Island, the entertainment hub about 30 minutes from the center of downtown. Mingling among the\u2026 [+1785 chars]"
}, ... ]
sqlmanager.py:
def populateNewsLatest(jsonpacket):
# print(jsonpacket)
with pyodbc.connect('DRIVER=' + driver +
';SERVER=tcp:' + server +
';PORT=1433;DATABASE=' +
database +
';UID=' + username + ';PWD=' + password) as conn:
conn.autocommit = True
with conn.cursor() as curse:
if curse.tables('newslatest').fetchone():
# delete if table exists
curse.execute('DROP TABLE [dbo].[newslatest]')
print('delete news latest/update')
# create new instance
curse.execute(
'CREATE TABLE newslatest(author varchar(28),content varchar(max),description varchar(max),publishedAt varchar(28),title varchar(28),url varchar(28),urlToImage varchar(28),id varchar(28),name varchar(28));')
json_string = json.dumps(jsonpacket)
print(json_string)
# dump json data to sql
curse.execute(f"""
DECLARE @json NVARCHAR(MAX)
SET @json=N'{json_string}';
INSERT INTO [dbo].[newslatest]
SELECT * FROM OPENJSON(@json) WITH(author varchar(28) '$.author',content nvarchar(max) '$.content',description nvarchar(max) '$.description',
publishedAt varchar(28) '$.publishedAt',title varchar(28) '$.title',url nvarchar(max) '$.url',
urlToImage nvarchar(max) '$.urlToImage',id varchar(28) '$.source.id',name varchar(28) '$.source.name');""")
return {"message": "successfully updated"}
else:
print('first time creation news latest')
curse.execute(
'CREATE TABLE newslatest(author varchar(28),content varchar(max),description varchar(max),publishedAt varchar(28),title varchar(28),url varchar(28),urlToImage varchar(28),id varchar(28),name varchar(28));')
json_string = json.dumps(jsonpacket)
curse.execute(f"""
DECLARE @json NVARCHAR(MAX)
SET @json=N'{json_string}';
INSERT INTO [dbo].[newslatest]
SELECT * FROM OPENJSON(@json) WITH(author varchar(28) '$.author',content nvarchar(max) '$.content',description nvarchar(max) '$.description',
publishedAt varchar(28) '$.publishedAt',title varchar(28) '$.title',url nvarchar(max) '$.url',
urlToImage nvarchar(max) '$.urlToImage',id varchar(28) '$.source.id',name varchar(28) '$.source.name');""")
return {"message": "successfully updated(first creation)"}
【问题讨论】:
-
使用 f-string 和
SET @json=N'{json_string}'会让您对 SQL 注入开放。如果json_string包含'{"name": "O\'Rourke"}'会发生什么?相反,使用参数占位符 (?) 并将 JSON 字符串作为参数传递给.execute()语句。 -
@GordThompson 我尝试使用占位符并替换了像
SET @json=N?;这样的json_string,但我现在收到此错误:'42S22, "[42S22] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Invalid column name 'N@P1'. (207) (SQLExecDirectW); [42S22] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Statement(s) could not be prepared. (8180) -
试试
SET @json=?;(虽然你真的不需要那个变量;你可以在语句本身中使用?参数占位符。 -
谢谢,我绝对不需要额外的变量,我直接用占位符就行了。
标签: azure azure-sql-database pyodbc azure-sql-server open-json