Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Jak wywołać procedurę składowaną za pomocą SQLAlchemy, która wymaga parametru tabeli zdefiniowanego przez użytkownika?

Istnieje sterownik, który naprawdę obsługuje programy TVP:Pytds . Nie jest oficjalnie obsługiwany, ale istnieje dla niego implementacja dialektu innej firmy:sqlalchemy-pytds . Korzystając z nich, możesz wywołać procedurę składowaną w następujący sposób:

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

W ten sposób możesz przekazać potencjalnie duże ilości danych 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',)

Jeśli z drugiej strony używasz sterownika, który nie obsługuje programów TVP, możesz deklaruj zmienną tabeli , wstaw wartości i przekaż to jako argument do Twojej procedury:

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

Zwróć uwagę, że nie możesz użyć żadnych metod executewielu, w przeciwnym razie wywołasz procedurę osobno dla każdej wartości tabeli. Dlatego symbole zastępcze są konstruowane ręcznie, a wartości tabeli przekazywane jako pojedyncze argumenty. Należy uważać, aby nie formatować żadnych argumentów bezpośrednio w zapytaniu, ale zamiast tego poprawną liczbę symboli zastępczych dla DB-API. Wartości wierszy są ograniczone do maksymalnie 1000 .

Byłoby oczywiście miło, gdyby bazowy sterownik DB-API zapewniał odpowiednią obsługę parametrów o wartościach tabelarycznych, ale przynajmniej nie mogłem znaleźć sposobu na pymssql, który używa FreeTDS. odniesienie do TVP na liście dyskusyjnej wyjaśnia, że ​​nie są obsługiwane. Sytuacja jest niewiele lepsza dla PyODBC .

Zastrzeżenie:Tak naprawdę nie używałem wcześniej 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. Dostawca nie zwrócił ciągu ProviderManifestToken

  2. Pobierz wiersze jako kolumny w sqlserver 2008

  3. Sposoby przechowywania historii danych w bazie danych SQL Server 2008

  4. Nie można połączyć się z serwerem raportów 2008 r2

  5. Kolumna jest w konflikcie z typem innych kolumn na liście unpivot