#sql-server
Вопрос:
У меня есть хранимая процедура, код:
DECLARE @RC int
DECLARE @id varchar(13)
DECLARE @pw varchar(13)
DECLARE @depart varchar(32)
DECLARE @class varchar(12)
DECLARE @name varchar(12)
DECLARE @birthday varchar(10)
DECLARE @grade int
DECLARE @subgrade int
SELECT @id = 'test'
SELECT @pw = '12345'
SELECT @depart = 'none'
SELECT @class = 'GM'
SELECT @name = 'name'
SELECT @birthday = 'None'
SELECT @grade = 3
SELECT @subgrade = 2
EXEC @RC = [my_database].[dbo].[my_table] @id, @pw, @depart, @class, @name, @birthday, @grade, @subgrade
DECLARE @PrnLine nvarchar(4000)
PRINT 'Stored Procedure: my_database.dbo.my_table'
SELECT @PrnLine = ' Return Code = ' CONVERT(nvarchar, @RC)
Как я могу сделать необработанный sql-запрос для создания учетной записи с помощью этой процедуры?
Я использую колбу и pyodbc.
Ответ №1:
Чтобы вызвать хранимую процедуру прямо сейчас, передайте вызов методу execute, используя либо формат, который распознает ваша база данных, либо формат escape-вызова ODBC. (Затем драйвер ODBC переформатирует вызов для вас в соответствии с данной базой данных.)
Для SQL Server вы бы использовали что — то вроде этого:
# SQL Server format
cursor.execute("exec sp_dosomething(123, 'abc')")
# ODBC format
cursor.execute("{call sp_dosomething(123, 'abc')}")
Итак, назовем вашу процедуру
id_ = 'test'
pw = '12345'
depart = 'none'
class_ = 'GM'
name = 'name'
birthday = 'None'
grade = 3
subgrade = 2
sql = 'exec [my_database].[dbo].[my_table](?, ?, ?, ?, ?, ?, ?, ?)'
values = (id_, pw, depart, class_, name, birthday, grade, subgrade)
cursor.execute(sql, (values))
Комментарии:
1. здесь проблема: ошибка программирования sqlalchemy.exc.: (Ошибка программирования) (‘42000’, «[42000] [Microsoft][Драйвер ODBC SQL Server][SQL Server]Неправильный синтаксис рядом с ‘@P1’. (102) (SQLExecDirectW)») ‘exe my_procedure(?, ?, ?)’ (‘5215125’, ‘125151’, ‘31231’)
2. Это похоже на синтаксическую ошибку в хранимой процедуре. Является
@P1
ли частью настоящего?3. Спасибо, sql = ‘exec [my_database]. [dbo]. [my_table] ?, ?, ?, ?, ?, ?, ?, ?’ работает нормально(без скобок).
4. Без скобок работает, если в именах нет пробелов, если у вас есть пробелы, вам нужны скобки…..
5. Всем привет, пожалуйста, как получить возвращаемое значение если моя хранимая процедура имеет идентификатор SELECT IDENT_CURRENT («ТАБЛИЦА») в качестве идентификатора, я хочу получить идентификатор.
Ответ №2:
Принятый ответ не решает проблему получения возвращаемого значения из хранимой процедуры, что можно сделать следующим образом:
id_ = 'test'
pw = '12345'
depart = 'none'
class_ = 'GM'
name = 'name'
birthday = 'None'
grade = 3
subgrade = 2
sql = """
SET NOCOUNT ON;
DECLARE @RC int;
EXEC @RC = [my_database].[dbo].[my_sp] ?, ?, ?, ?, ?, ?, ?, ?;
SELECT @RC AS rc;
"""
values = (id_, pw, depart, class_, name, birthday, grade, subgrade)
cursor.execute(sql, values)
rc = cursor.fetchval() # pyodbc convenience method similar to cursor.fetchone()[0]
Ответ №3:
Не забудьте включить NOCOUNT в вашей хранимой процедуре.
Комментарии:
1. Это действительно помогло нам справиться с проблемой, когда SP не работает. И все же я не понимаю, как это может быть фактором
Ответ №4:
Другой вариант ответа Горда заключается в использовании выходных и именованных параметров (которые должны быть определены в хранимой процедуре) для ясности.
id_ = 'test'
pw = '12345'
depart = 'none'
class_ = 'GM'
name = 'name'
birthday = 'None'
grade = 3
subgrade = 2
sql = """
DECLARE @RC int;
EXEC [my_database].[dbo].[my_sp] @RC OUTPUT, @id_=?, @pw=?, @depart=?, @class_=?, @name=?, @birthday=?, @grade=?, @subgrade=?;
SELECT @RC AS rc;
"""
values = (id_, pw, depart, class_, name, birthday, grade, subgrade)
cursor.execute(sql, values)
rc = cursor.fetchval()
Ответ №5:
С помощью курсора, инициализированного вашим подключением, sp можно вызвать напрямую следующим образом
sql = " exec your_SP @codemp = ?, @fecha = ? "
prm = (dict['param1'], dict['param2'])
cursor.execute(qry, params)
Ответ №6:
После того, как я повсюду искал это решение, я не смог найти упрощенную версию. Все результаты, по-видимому, чрезмерно усложняют это, что должно быть так легко сделать. Вот мое решение.
import pyodbc
import pandas as pd
import datetime as d
conn = pyodbc.connect('Driver=;'
'Server=;'
'Database=;'
'UID=;'
'PWD=;')
# define parameters to be passed in and out
quarter_date = d.date(year=2020, month=10, day=1)
SQL = r'exec TERRITORIES_SP @quarterStart = ' "'" str(quarter_date) "'"
print(SQL)
try:
cursor = conn.cursor()
cursor.execute(SQL)
cursor.close()
conn.commit()
finally:
conn.close()
Комментарии:
1. Используя динамический SQL, вы оставляете себя открытым для уязвимостей SQL — инъекций.
2. Спасибо. Каков был бы лучший подход?
3. Что-то вроде
sql = r'exec TERRITORIES_SP @quarterStart = ?'
последовало заcursor.execute(sql, str(quarter_date))
этим . Я признаю, что в этом случае риск внедрения SQL невелик, но все равно было бы дурным тоном продвигать динамический SQL как «упрощенное» решение.
Ответ №7:
Для MSSQL правильным форматом является следующий:
SQL = 'exec sp_UpdateUserGoogleAuthenticated ''?'', ''?'''
Попробуйте запустить хранимую процедуру в MSSQL в окне SQL-запроса, и она будет завершаться ошибкой каждый раз, когда () окружает ? Метки. Если вы уберете одинарные кавычки, это позволит использовать переменные с пробелами в них.