Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Как да извикате съхранена процедура с SQLAlchemy, която изисква дефиниран от потребителя тип таблица параметър

Има драйвер, който наистина поддържа TVP:Pytds . Не се поддържа официално, но има реализация на диалект от трета страна за него:sqlalchemy-pytds . Използвайки ги, можете да извикате вашата съхранена процедура така:

In [1]: engine.execute(DDL("CREATE TYPE [dbo].[StringTable] AS TABLE([strValue] [nvarchar](max) NULL)"))
Out[1]: <sqlalchemy.engine.result.ResultProxy at 0x7f235809ae48>

In [2]: engine.execute(DDL("CREATE PROC test_proc (@pArg [StringTable] READONLY) AS BEGIN SELECT * FROM @pArg END"))
Out[2]: <sqlalchemy.engine.result.ResultProxy at 0x7f2358027b70>

In [3]: arg = ['Name One', 'Name Two']

In [4]: import pytds

In [5]: tvp = pytds.TableValuedParam(type_name='StringTable',
   ...:                              rows=((x,) for x in arg))

In [6]: engine.execute('EXEC test_proc %s', (tvp,))
Out[6]: <sqlalchemy.engine.result.ResultProxy at 0x7f294e699e10>

In [7]: _.fetchall()
Out[7]: [('Name One',), ('Name Two',)]

По този начин можете да предавате потенциално големи количества данни като параметри:

In [21]: tvp = pytds.TableValuedParam(type_name='StringTable',
    ...:                              rows=((str(x),) for x in range(100000)))

In [22]: engine.execute('EXEC test_proc %s', (tvp,))
Out[22]: <sqlalchemy.engine.result.ResultProxy at 0x7f294c6e9f98>

In [23]: _.fetchall()[-1]
Out[23]: ('99999',)

Ако от друга страна използвате драйвер, който не поддържа TVP, можете да деклариране на променлива на таблица , вмъкнете стойностите и предайте това като аргумент към вашата процедура:

In [12]: engine.execute(
    ...:     """
    ...:     DECLARE @pArg AS [StringTable];
    ...:     INSERT INTO @pArg VALUES {placeholders};
    ...:     EXEC test_proc @pArg;
    ...:     """.format(placeholders=",".join(["(%s)"] * len(arg))),
    ...:     tuple(arg))
    ...:     
Out[12]: <sqlalchemy.engine.result.ResultProxy at 0x7f23580f2908>

In [15]: _.fetchall()
Out[15]: [('Name One',), ('Name Two',)]

Обърнете внимание, че не можете да използвате никакви методи за изпълнение на много или в крайна сметка ще извикате процедурата за всяка стойност на таблицата поотделно. Ето защо контейнерите се конструират ръчно и стойностите на таблицата се предават като отделни аргументи. Трябва да се внимава да не се форматират никакви аргументи директно в заявката, а вместо това правилното количество контейнери за DB-API. Стойностите на реда са ограничени до максимум 1000 .

Разбира се, би било хубаво, ако основният DB-API драйвер осигури подходяща поддръжка за параметри с таблична стойност, но поне не можах да намеря начин за pymssql, който използва FreeTDS. препратка към TVP в пощенския списък показва ясно, че не се поддържат. Ситуацията не е много по-добра за PyODBC .

Отказ от отговорност:Не съм използвал наистина MS SQL Server преди.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Доставчикът на OLE DB Microsoft.ACE.OLEDB.12.0 за свързан сървър (null) върна съобщение Отметката е невалидна.

  2. Sql Server 2008 географски ограничения за размера на LineString

  3. как да проверите уникалността (без дублиране) на публикация в rss емисия

  4. SQL - Свързване към свързан сървър с именуван екземпляр

  5. Актуализиране на пощенски акаунт в база данни в SQL Server (T-SQL)