sql >> Databáze >  >> RDS >> Sqlserver

Jak volat uloženou proceduru s SQLAlchemy, která vyžaduje parametr tabulky uživatelského typu

Existuje ovladač, který skutečně podporuje TVP:Pytds . Není oficiálně podporován, ale existuje pro něj implementace dialektu třetí strany:sqlalchemy-pytds . Pomocí nich můžete svou uloženou proceduru nazvat takto:

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',)]

Tímto způsobem můžete předávat potenciálně velké množství dat jako parametry:

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',)

Pokud na druhou stranu používáte ovladač, který nepodporuje TVP, můžete deklarovat proměnnou tabulky , vložte hodnoty a předejte to jako argument k vašemu postupu:

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',)]

Všimněte si, že nemůžete použít žádné spouštěcí metody, nebo skončíte voláním procedury pro každou hodnotu tabulky zvlášť. Proto jsou zástupné symboly konstruovány ručně a hodnoty tabulky jsou předávány jako jednotlivé argumenty. Je třeba dbát na to, abyste neformátovali žádné argumenty přímo do dotazu, ale místo toho správný počet zástupných symbolů pro DB-API. Hodnoty řádků jsou omezeny na maximálně 1000 .

Bylo by samozřejmě hezké, kdyby základní ovladač DB-API poskytoval správnou podporu pro parametry s hodnotou tabulky, ale alespoň jsem nenašel cestu pro pymssql, který používá FreeTDS. odkaz na TVP na seznamu adresátů dává jasně najevo, že nejsou podporovány. Situace není o moc lepší pro PyODBC .

Odmítnutí odpovědnosti:Ve skutečnosti jsem MS SQL Server dříve nepoužíval.



  1. Jak přihlásit nového uživatele k odběru upozornění?

  2. Postgresql – dynamicky vytvořte databázi a tabulku

  3. Získání odpovědi HTML namísto JSON v systému Android

  4. Automatické zvýšení primárního klíče PostgreSQL 9.1