【问题标题】:pyodbc azure sql server error in saving json using openjson使用openjson保存json时pyodbc azure sql server错误
【发布时间】: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


【解决方案1】:

以下是需要检查的几件事:

  1. 按照 Gord 的建议,检查 json 字符串。

  2. 如果我们有更多数据,我们可以使用 executemany 来运行命令,因为执行可能会导致计数问题。

  3. 您也可以通过以下方式使用它:

     sql = "INSERT INTO #temptable VALUES (........)" 
     vals = data.to_numpy().tolist()
     con.executemany(sql_insert, vals)
    

连同上述建议,请参阅SOdiscuss.dizzycoding 答案。感谢回答的技术人员。

【讨论】:

    猜你喜欢
    • 2021-10-08
    • 1970-01-01
    • 2022-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-16
    • 1970-01-01
    相关资源
    最近更新 更多