zillow / ctds

Python DB-API 2.0 library for MS SQL Server

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Execute vs ExecuteMany

chad-ongstad opened this issue · comments

I seem to get 2 different result sets when using executemany vs. execute when inserting data. I have included an example below that shows how the last 3 records insert differently using execute vs. execute many. I am happy to help out if you can point me in the right direction in the code base. Thanks,

Chad

import ctds
dropStmnt='drop table if exists demoSource_sales.W_salesorderdetail'

createStmnt="""Create table  [demoSource_sales].[W_salesorderdetail]
             (  [salesorderid] int
              , [salesorderdetailid] int
              , [carriertrackingnumber] nvarchar(25)
              , [orderqty] smallint
              , [productid] int
              , [specialofferid] int
              , [unitprice] numeric
              , [unitpricediscount] numeric
              , [rowguid] char(36)
              , [modifieddate] datetime2
             ) """

insertStmnt="""Insert into demoSource_sales.W_salesorderdetail             
                       (salesorderid
                        ,salesorderdetailid
                        ,carriertrackingnumber
                        ,orderqty
                        ,productid
                        ,specialofferid
                        ,unitprice
                        ,unitpricediscount
                        ,rowguid
                        ,modifieddate) 
                values (cast( :0 as int)
                        ,cast( :1 as int)
                        ,cast( :2 as nvarchar(25))
                        ,cast( :3 as smallint)
                        ,cast( :4 as int)
                        ,cast( :5 as int)
                        ,cast( :6 as numeric)
                        ,cast( :7 as numeric)
                        ,cast( :8 as char(36))
                        ,cast( :9 as datetime2))"""

dataSet=[
           [u'43659', u'1', u'4911-403C-98', u'1', u'776', u'1', u'2024.994', u'0', u'b207c96d-d9e6-402b-8470-2cc176c42283', u'2011-05-31 00:00:00']
         , [u'43659', u'2', u'4911-403C-98', u'3', u'777', u'1', u'2024.994', u'0', u'7abb600d-1e77-41be-9fe5-b9142cfc08fa', u'2011-05-31 00:00:00']
         , [u'43659', u'3', u'4911-403C-98', u'1', u'778', u'1', u'2024.994', u'0', u'475cf8c6-49f6-486e-b0ad-afc6a50cdd2f', u'2011-05-31 00:00:00']
         , [u'43659', u'4', u'4911-403C-98', u'1', u'771', u'1', u'2039.994', u'0', u'04c4de91-5815-45d6-8670-f462719fbce3', u'2011-05-31 00:00:00']
         , [u'43659', u'5', u'4911-403C-98', u'1', u'772', u'1', u'2039.994', u'0', u'5a74c7d2-e641-438e-a7ac-37bf23280301', u'2011-05-31 00:00:00']
         , [u'43659', u'6', u'4911-403C-98', u'2', u'773', u'1', u'2039.994', u'0', u'ce472532-a4c0-45ba-816e-eefd3fd848b3', u'2011-05-31 00:00:00']
         , [u'43659', u'7', u'4911-403C-98', u'1', u'774', u'1', u'2039.994', u'0', u'80667840-f962-4ee3-96e0-aeca108e0d4f', u'2011-05-31 00:00:00']
         , [u'43659', u'8', u'4911-403C-98', u'3', u'714', u'1', u'28.8404', u'0', u'e9d54907-e7b7-4969-80d9-76ba69f8a836', u'2011-05-31 00:00:00']
         , [u'43659', u'9', u'4911-403C-98', u'1', u'716', u'1', u'28.8404', u'0', u'aa542630-bdcd-4ce5-89a0-c1bf82747725', u'2011-05-31 00:00:00']
         , [u'43659', u'10', u'4911-403C-98', u'6', u'709', u'1', u'5.7', u'0', u'ac769034-3c2f-495c-a5a7-3b71cdb25d4e', u'2011-05-31 00:00:00']
         , [u'43659', u'11', u'4911-403C-98', u'2', u'712', u'1', u'5.1865', u'0', u'06a66921-6b9f-4199-a912-ddafd383472b', u'2011-05-31 00:00:00']
         , [u'43659', u'12', u'4911-403C-98', u'4', u'711', u'1', u'20.1865', u'0', u'0e371ee3-253e-4bb0-b813-83cf4224f972', u'2011-05-31 00:00:00']
        ]

con_args={'server':'xxx.xxx.x.x','port':1433,'user':'xx','password':'xxxxxx','database':'xxxx','timeout':86400}

conn=ctds.connect(**con_args)
cursor=conn.cursor()

cursor.execute(dropStmnt)
cursor.execute(createStmnt)
cursor.executemany(insertStmnt,dataSet)

cursor.execute('select * from demoSource_sales.W_salesorderdetail')

result=cursor.fetchall()

for r in result:
    print tuple(r)


print '#'*20

cursor.execute('truncate table demoSource_sales.W_salesorderdetail')


for row in dataSet:
    cursor.execute(insertStmnt,row)

cursor.execute('select * from demoSource_sales.W_salesorderdetail')

result=cursor.fetchall()

for r in result:
    print tuple(r)

Returns the following

(43659L, 1L, u'4911-403C-98', 1L, 776L, 1L, Decimal('2025'), Decimal('0'), u'b207c96d-d9e6-402b-8470-2cc176c42283', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 2L, u'4911-403C-98', 3L, 777L, 1L, Decimal('2025'), Decimal('0'), u'7abb600d-1e77-41be-9fe5-b9142cfc08fa', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 3L, u'4911-403C-98', 1L, 778L, 1L, Decimal('2025'), Decimal('0'), u'475cf8c6-49f6-486e-b0ad-afc6a50cdd2f', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 4L, u'4911-403C-98', 1L, 771L, 1L, Decimal('2040'), Decimal('0'), u'04c4de91-5815-45d6-8670-f462719fbce3', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 5L, u'4911-403C-98', 1L, 772L, 1L, Decimal('2040'), Decimal('0'), u'5a74c7d2-e641-438e-a7ac-37bf23280301', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 6L, u'4911-403C-98', 2L, 773L, 1L, Decimal('2040'), Decimal('0'), u'ce472532-a4c0-45ba-816e-eefd3fd848b3', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 7L, u'4911-403C-98', 1L, 774L, 1L, Decimal('2040'), Decimal('0'), u'80667840-f962-4ee3-96e0-aeca108e0d4f', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 8L, u'4911-403C-98', 3L, 714L, 1L, Decimal('29'), Decimal('0'), u'e9d54907-e7b7-4969-80d9-76ba69f8a836', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 9L, u'4911-403C-98', 1L, 716L, 1L, Decimal('29'), Decimal('0'), u'aa542630-bdcd-4ce5-89a0-c1bf82747725', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 1L, u'4911-403C-98', 6L, 709L, 1L, Decimal('6'), Decimal('0'), u'ac769034-3c2f-495c-a5a7-3b71cdb25d4e', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 1L, u'4911-403C-98', 2L, 712L, 1L, Decimal('5'), Decimal('0'), u'06a66921-6b9f-4199-a912-ddafd383472b', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 1L, u'4911-403C-98', 4L, 711L, 1L, Decimal('20'), Decimal('0'), u'0e371ee3-253e-4bb0-b813-83cf4224f972', datetime.datetime(2011, 5, 31, 0, 0))
####################
(43659L, 1L, u'4911-403C-98', 1L, 776L, 1L, Decimal('2025'), Decimal('0'), u'b207c96d-d9e6-402b-8470-2cc176c42283', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 2L, u'4911-403C-98', 3L, 777L, 1L, Decimal('2025'), Decimal('0'), u'7abb600d-1e77-41be-9fe5-b9142cfc08fa', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 3L, u'4911-403C-98', 1L, 778L, 1L, Decimal('2025'), Decimal('0'), u'475cf8c6-49f6-486e-b0ad-afc6a50cdd2f', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 4L, u'4911-403C-98', 1L, 771L, 1L, Decimal('2040'), Decimal('0'), u'04c4de91-5815-45d6-8670-f462719fbce3', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 5L, u'4911-403C-98', 1L, 772L, 1L, Decimal('2040'), Decimal('0'), u'5a74c7d2-e641-438e-a7ac-37bf23280301', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 6L, u'4911-403C-98', 2L, 773L, 1L, Decimal('2040'), Decimal('0'), u'ce472532-a4c0-45ba-816e-eefd3fd848b3', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 7L, u'4911-403C-98', 1L, 774L, 1L, Decimal('2040'), Decimal('0'), u'80667840-f962-4ee3-96e0-aeca108e0d4f', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 8L, u'4911-403C-98', 3L, 714L, 1L, Decimal('29'), Decimal('0'), u'e9d54907-e7b7-4969-80d9-76ba69f8a836', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 9L, u'4911-403C-98', 1L, 716L, 1L, Decimal('29'), Decimal('0'), u'aa542630-bdcd-4ce5-89a0-c1bf82747725', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 10L, u'4911-403C-98', 6L, 709L, 1L, Decimal('6'), Decimal('0'), u'ac769034-3c2f-495c-a5a7-3b71cdb25d4e', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 11L, u'4911-403C-98', 2L, 712L, 1L, Decimal('5'), Decimal('0'), u'06a66921-6b9f-4199-a912-ddafd383472b', datetime.datetime(2011, 5, 31, 0, 0))
(43659L, 12L, u'4911-403C-98', 4L, 711L, 1L, Decimal('20'), Decimal('0'), u'0e371ee3-253e-4bb0-b813-83cf4224f972', datetime.datetime(2011, 5, 31, 0, 0))

This is due to the implementation of executemany, which internally uses sp_executesql for better performance (and to avoid the possibility of SQL injection). The sequence in the parameter set is used to determine the SQL type to declare for each of the parameters passed to sp_executesql. in this case, you have a string of length 1, so the type is inferred as CHAR(1). Of course later items in the parameter set may have values longer than 1 character and are truncated.

It should be fairly easy to default to SQL type inference to default to the largest widths of the variable sized SQL types for this case. In the meantime, you could explicitly specify the SQL type for the string columns using a type wrapper such as: https://zillow.github.io/ctds/types.html#ctds.SqlNVarChar

Alternatively passing the INT columns as Python int (or long) objects would also avoid the truncation issue.

Fixed in v1.8.0.