【问题标题】:Update SQL Server database using stored procedure with table as paramater using PYODBC in Python在 Python 中使用以表为参数的存储过程更新 SQL Server 数据库
【发布时间】:2020-06-29 22:11:01
【问题描述】:

我需要使用存储过程和使用PYODBC 的表作为参数来更新 SQL Server 数据库。存储过程应该没问题,但我不确定 Python 脚本中使用的语法:

Python:

import pandas as pd
import pyodbc

# Create dataframe
data = pd.DataFrame({
    'STATENAME':[state1, state2],
    'COVID_Cases':[value1, value2],
})

data

conn = pyodbc.connect('Driver={SQL Server};'
                      'Server=mydb;'
                      'Database=mydbname;'
                      'Username=username'
                      'Password=password'
                      'Trusted_Connection=yes;')

cursor = conn.cursor()

params = ('@StateValues', data)
cursor.execute("{CALL spUpdateCases (?,?)}", params)

存储过程:

[dbo].[spUpdateCases]
    @StateValues tblTypeCOVID19 readonly,
    @Identity int out
AS
BEGIN
    INSERT INTO tblCOVID19 
        SELECT * FROM @StateValues

    SET @Identity = SCOPE_IDENTITY()
END

这是我的用户定义类型:

CREATE TYPE [dbo].[tblTypeCOVID19] AS TABLE
                                      (
                                          [ID] [int] NOT NULL,
                                          [StateName] [varchar](50) NULL,
                                          [COVID_Cases] [int] NULL,
                                          [DateEntered] [datetime] NULL
                                      )

执行 Python 脚本时我没有收到任何错误。

【问题讨论】:

  • 您为什么要使用可信连接传递用户名和密码?这是其中之一,而不是两者。
  • @Larnu 谢谢,我会解决这个问题。只是想先让它工作,然后计划照顾它。不确定如何传递用户/通行证。
  • 请添加 tblTypeCOVID19 的类型定义。
  • @DavidBrowne-Microsoft - 我已将我的用户定义类型添加到帖子中。谢谢。
  • 您需要commit您的更改。这是 Python DB-API 问题的常见问题。

标签: python sql-server stored-procedures


【解决方案1】:

直接使用表值参数需要客户端支持,我认为 pyodbc 尚未实现。但从 python 读取和写入表格数据的最佳方式是使用 JSON。

您可以将表格结果作为 JSON 发送到 SQL Server,并解析服务器上的文档以加载 TVP 或常规表。

这是一个演练。另外,我已经修改了您的存储过程以返回多行结果,而不仅仅是单个 SCOPE_IDENTITY 值:

在 SQL Server 中运行:

use tempdb

go
drop table if exists tblCOVID19
drop procedure [spUpdateCases]
drop type [dbo].[tblTypeCOVID19]
go
create table tblCOVID19
(
  ID int identity not null primary key,
  StateName varchar(200), 
  COVID_Cases int, 
  DateEntered datetime default getdate()
)
go
CREATE TYPE [dbo].[tblTypeCOVID19] AS TABLE(
[ID] [int] NULL,
[StateName] [varchar](50) NULL,
[COVID_Cases] [int] NULL,
[DateEntered] [datetime] NULL
)

go
create or alter procedure [dbo].[spUpdateCases]
@StateValues tblTypeCOVID19 readonly
AS
BEGIN
  set nocount on; 

  insert into tblCOVID19 (StateName, COVID_Cases)
  output inserted.*
  select StateName, COVID_Cases 
  from @StateValues;

END

并验证它是否在 TSQL 中像这样工作:

declare @json nvarchar(max) = '[{"STATENAME":"TX","COVID_Cases":212},{"STATENAME":"OK","COVID_Cases":41}]'

declare @tvp tblTypeCOVID19

insert into @tvp(StateName, COVID_Cases)
select StateName, COVID_Cases
from openjson(@json)
with 
(
  StateName varchar(200) '$.STATENAME',
  COVID_Cases int '$.COVID_Cases'
)

exec [dbo].[spUpdateCases] @tvp

然后像这样从 python 调用它:

import pandas as pd
import pyodbc
import json

# Create dataframe
data = pd.DataFrame({
    'STATENAME':["TX", "OK"],
    'COVID_Cases':[212, 41],
})



conn = pyodbc.connect('Driver={SQL Server};'
                      'Server=localhost;'
                      'Database=tempdb;'
                      'Trusted_Connection=yes;')

cursor = conn.cursor()

jsonData = data.to_json(orient='records')
print(jsonData)

sql = """
set nocount on;
declare @tvp tblTypeCOVID19

insert into @tvp(StateName, COVID_Cases)
select StateName, COVID_Cases
from openjson(?)
with 
(
  StateName varchar(200) '$.STATENAME',
  COVID_Cases int '$.COVID_Cases'
)

exec [dbo].[spUpdateCases] @tvp
"""
cursor.execute(sql, jsonData)
results = cursor.fetchall()

print(results)

【讨论】:

    猜你喜欢
    • 2023-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-12
    • 2018-11-27
    相关资源
    最近更新 更多