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

    executemanyメソッドを使用できないことに注意してください。そうしないと、テーブル値ごとに個別にプロシージャを呼び出すことになります。そのため、プレースホルダーは手動で作成され、テーブル値は個別の引数として渡されます。引数をクエリに直接フォーマットするのではなく、代わりにDB-APIの正しい量のプレースホルダーをフォーマットするように注意する必要があります。行の値は最大1000 。

    もちろん、基盤となるDB-APIドライバーがテーブル値パラメーターを適切にサポートしていれば便利ですが、少なくともFreeTDSを使用するpymssqlの方法を見つけることができませんでした。 メーリングリストのTVPへの参照 それらがサポートされていないことを明確にします。状況はPyODBCにとってそれほど良くない です。 。

    免責事項:これまでMSSQLServerを実際に使用したことはありません。



    1. MySQLでロールを使用して特権を管理する方法

    2. 異なるデータ型の動的列を含むフラット ファイルを Oracle データベースにロードする方法は?

    3. ある列のSQLグループ値を別の列ごとに

    4. MySQL –影響を受ける行の総数に対するFOUND_ROWS()関数