एक ड्राइवर है जो वास्तव में टीवीपी का समर्थन करता है: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',)]
ध्यान दें कि आप किसी भी एक्ज़ीक्यूटमैनी विधियों का उपयोग नहीं कर सकते हैं, या आप प्रत्येक तालिका मान के लिए अलग से प्रक्रिया को कॉल करना समाप्त कर देंगे। यही कारण है कि प्लेसहोल्डर मैन्युअल रूप से बनाए जाते हैं और तालिका मान अलग-अलग तर्कों के रूप में पारित होते हैं। किसी भी तर्क को सीधे क्वेरी में प्रारूपित करने के लिए नहीं, बल्कि डीबी-एपीआई के लिए प्लेसहोल्डर्स की सही मात्रा का ध्यान रखा जाना चाहिए। पंक्ति मान एक अधिकतम 1000 ।
यह निश्चित रूप से अच्छा होगा, यदि अंतर्निहित डीबी-एपीआई ड्राइवर ने तालिका मूल्यवान पैरामीटर के लिए उचित समर्थन प्रदान किया है, लेकिन कम से कम मुझे pymssql के लिए कोई रास्ता नहीं मिला, जो फ्रीटीडीएस का उपयोग करता है। एक मेलिंग सूची में टीवीपी का संदर्भ यह स्पष्ट करता है कि वे समर्थित नहीं हैं। स्थिति PyODBC के लिए बेहतर नहीं है ।
<उप>अस्वीकरण:मैंने पहले वास्तव में MS SQL सर्वर का उपयोग नहीं किया है।