【问题标题】:Simplest way to insert variables into SQL Stored Procedure using Python?使用 Python 将变量插入 SQL 存储过程的最简单方法?
【发布时间】:2018-02-08 19:05:54
【问题描述】:

我有一个想要概括的存储 SQL 过程。这涉及将表名称、开始时间和结束时间作为变量传递,因此不必每次都编辑过程。我正在尝试使用基本的 python 变量来提示用户。 (Start = int(input("输入开始时间:")) 我只是还没有找到一个简单的方法来做到这一点。我已经使用了“执行 sp_execute_external_scripts”,并且一直在查看 Pyodbc 是否是正确的工具,但到目前为止没有任何效果,而且我没有完全理解用于创建包装器的 MS 文档/教程。那么提示用户输入可以作为变量注入过程的最简单方法是什么?我觉得我在这里遗漏了一些非常简单的东西。

在这里阅读 cmets 后,我的原始方法过于宽泛,需要使用 dynamicsql,我并不自动反对,但为单个表创建过程似乎更安全。所以我只需要将 Start、End 和 ChunkSize 作为整数变量推送到过程中。

已解决:我通过使用 pyodbc 编写一个小型 python 程序得到了预期的结果。感谢您的帮助和温柔地摆脱我最初的幼稚想法。

import pyodbc
connection = pyodbc.connect('Driver={SQL Server};'
                            'Server=CROWN;'
                            'Database=ControlInformation;'
                            'Trusted_Connection=yes;')


cursor = connection.cursor()

Start = int(input("Enter Start Time: "))
End = int(input("Enter End Time: "))
ChunkSize = int(input("Enter # of files to delete at once: "))
cursor.execute('exec PurgeCurrencyExchangeRates @start = %d, @end = %d, 
@ChunkSize = %d' %(Start, End, ChunkSize))
cursor.commit(), 
connection.close()

SQL 存储过程

CREATE PROCEDURE UserInput 
@r int = 1,
@Start bigint = 0, 
@End bigint = 0,
@TableName varchar(40) = 'CurrencyExchangeRates',
@ChunkSize int = 10000,
@ColumnName varchar(40) = 'Timestamp'

AS
BEGIN

SET NOCOUNT ON;

while @r > 0
    delete top(@ChunkSize)
        ControlInformation.dbo.@TableName
        where @ColumnName > @Start and @ColumnName < @End

    set @r = @@ROWCOUNT

【问题讨论】:

  • 为什么要创建一个通用的“从表 x 中删除所有数据”过程?您不能参数化表或列名,因此这需要动态 sql。但是又一次……为什么???这有点像在编程语言中创建一个通用的删除方法,您必须传入对象名称。
  • 动态传入表名表明您违反了关系数据库设计的常规规则。这应该是单个表中对数据进行分区的列。
  • 目的不是从表 X 中删除所有数据。我正在尝试删除两个日期范围之间的大量行。此外,我将其分块是因为一次删除的数据太多,并且会中断我们业务在数据库上运行的其他进程。
  • 我理解的分块部分。但是您正在制作一个可以从任何表中删除数据的过程。这表明您要么试图使其过于通用,要么您的架构被非规范化(或两者兼而有之)。
  • 好的@SeanLange,我将稍微改变我尝试解决此问题的方式。我应该为每个要删除的表创建一个过程,而不是过度概括吗? (摆脱 TableName 和 ColumnName)这很容易做到,但我仍然有将 Start、End 和 ChunkSize 作为变量而不是静态参数推送的潜在问题。用户输入是这里的主要目标。

标签: sql sql-server stored-procedures pyodbc


【解决方案1】:

存储过程应该是这样的:

use CurrencyExchangeRates
go
CREATE PROCEDURE PurgeCurrencyExchangeRates 
@Start bigint = 0, 
@End bigint = 0,
@ChunkSize int = 10000
AS
BEGIN
    SET NOCOUNT ON;
    declare @r int = 1;


    while @r > 0
    begin
        delete top(@ChunkSize)
            from dbo.CurrencyExchangeRates
            where [Timestamp] >= @Start and [Timestamp] < @End

        set @r = @@ROWCOUNT
    end

end

【讨论】:

  • 感谢您清理程序,似乎试图概括所有表是不好的形式。但是如何将 start、end 和 chunksize 集成为用户可以输入的变量?我知道 SQL 无法做到这一点,这就是我尝试编写一个小型 python 包装器的原因。
【解决方案2】:

也许你需要在 python 中:

Start = int(input("Enter Start Time: "))
sql = 'exec UserInput @start =?'
cursor.execute(sql, Start)
cursor.commit()

【讨论】:

    【解决方案3】:

    如果你真的想让表名动态那么你需要使用动态SQL,像这样:

    ALTER PROCEDURE DeleteFrom 
        @tableName sysname ='Table0'
    AS
    BEGIN
        SET NOCOUNT ON;
        DECLARE @sql nvarchar(4000);
        SET @sql = N'DELETE TOP (1) FROM ' + QUOTENAME(@tableName);
        EXEC(@sql);
    END
    

    【讨论】:

    • 这很容易受到 sql 注入的影响。至少你应该用 QUOTENAME 包装表名。
    猜你喜欢
    • 2018-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-02
    相关资源
    最近更新 更多