22

I am trying to write a csv file into a table in SQL Server database using python. I am facing errors when I pass the parameters , but I don't face any error when I do it manually. Here is the code I am executing.

cur=cnxn.cursor() # Get the cursor
csv_data = csv.reader(file(Samplefile.csv')) # Read the csv
for rows in csv_data: # Iterate through csv
    cur.execute("INSERT INTO MyTable(Col1,Col2,Col3,Col4) VALUES (?,?,?,?)",rows)
cnxn.commit()

Error:

pyodbc.DataError: ('22001', '[22001] [Microsoft][ODBC SQL Server Driver][SQL Server]String or binary data would be truncated. (8152) (SQLExecDirectW); [01000] [Microsoft][ODBC SQL Server Driver][SQL Server]The statement has been terminated. (3621)')

However when I insert the values manually. It works fine

cur.execute("INSERT INTO MyTable(Col1,Col2,Col3,Col4) VALUES (?,?,?,?)",'A','B','C','D')

I have ensured that the TABLE is there in the database, data types are consistent with the data I am passing. Connection and cursor are also correct. The data type of rows is "list"

1
  • Does your csv file contain column names in the first line? Commented Jan 21, 2014 at 14:09

8 Answers 8

43

Consider building the query dynamically to ensure the number of placeholders matches your table and CSV file format. Then it's just a matter of ensuring your table and CSV file are correct, instead of checking that you typed enough ? placeholders in your code.

The following example assumes

  1. CSV file contains column names in the first line
  2. Connection is already built
  3. File name is test.csv
  4. Table name is MyTable
  5. Python 3
...
with open ('test.csv', 'r') as f:
    reader = csv.reader(f)
    columns = next(reader) 
    query = 'insert into MyTable({0}) values ({1})'
    query = query.format(','.join(columns), ','.join('?' * len(columns)))
    cursor = connection.cursor()
    for data in reader:
        cursor.execute(query, data)
    cursor.commit()

If column names are not included in the file:

...
with open ('test.csv', 'r') as f:
    reader = csv.reader(f)
    data = next(reader) 
    query = 'insert into MyTable values ({0})'
    query = query.format(','.join('?' * len(data)))
    cursor = connection.cursor()
    cursor.execute(query, data)
    for data in reader:
        cursor.execute(query, data)
    cursor.commit()
Sign up to request clarification or add additional context in comments.

Comments

4

I modified the code written above by Brian as follows since the one posted above wouldn't work on the delimited files that I was trying to upload. The line row.pop() can also be ignored as it was necessary only for the set of files that I was trying to upload.

import csv

def upload_table(path, filename, delim, cursor):
    """
    Function to upload flat file to sqlserver
    """
    tbl = filename.split('.')[0]
    cnt = 0
    with open (path + filename, 'r') as f:
        reader = csv.reader(f, delimiter=delim)
        for row in reader:
            row.pop() # can be commented out
            row = ['NULL' if val == '' else val for val in row]
            row = [x.replace("'", "''") for x in row]
            out = "'" + "', '".join(str(item) for item in row) + "'"
            out = out.replace("'NULL'", 'NULL')
            query = "INSERT INTO " + tbl + " VALUES (" + out + ")"
            cursor.execute(query)
            cnt = cnt + 1
            if cnt % 10000 == 0:
                cursor.commit()
        cursor.commit()
    print("Uploaded " + str(cnt) + " rows into table " + tbl + ".")

2 Comments

there is no definition of 'csv' as in reader = csv.reader(...)
@donPablo - You need to import the csv library
1

I got it sorted out. The error was due to the size restriction restriction of table. It changed the column capacity like from col1 varchar(10) to col1 varchar(35) etc. Now it's working fine.

Comments

1

You can pass the columns as arguments. For example:

for rows in csv_data: # Iterate through csv
    cur.execute("INSERT INTO MyTable(Col1,Col2,Col3,Col4) VALUES (?,?,?,?)", *rows)

Comments

1

If you are using MySqlHook in airflow , if cursor.execute() with params throw san error

TypeError: not all arguments converted during string formatting

use %s instead of ?

with open('/usr/local/airflow/files/ifsc_details.csv','r') as csv_file:
    csv_reader = csv.reader(csv_file)
    columns = next(csv_reader)
    query = '''insert into ifsc_details({0}) values({1});'''
    query = query.format(','.join(columns), ','.join(['%s'] * len(columns)))
    mysql = MySqlHook(mysql_conn_id='local_mysql')
    conn = mysql.get_conn()
    cursor = conn.cursor()
    for data in csv_reader:
        cursor.execute(query, data)
    cursor.commit()

Comments

1

Here is the script and hope this works for you:

import pandas as pd    
import pyodbc as pc    
connection_string = "Driver=SQL Server;Server=localhost;Database={0};Trusted_Connection=Yes;"                           
cnxn = pc.connect(connection_string.format("DataBaseNameHere"), autocommit=True)    
cur=cnxn.cursor()
df= pd.read_csv("your_filepath_and_filename_here.csv").fillna('')    
query = 'insert into TableName({0}) values ({1})'    
query = query.format(','.join(df.columns), ','.join('?' * len(df1.columns)))        
cur.fast_executemany = True    
cur.executemany(query, df.values.tolist())
cnxn.close()

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
0

For my purposes, I was adding data to an existing table, and needed to be able to remove unnecessary columns. This is the code that worked for me:

# Read csv file and store data in the table
df = pd.read_csv('C:\\Users\\Admin\\Desktop\\data\\daily\\mx\\' + ticker_name + '.MX.csv')
df.columns =  ['date', 'open', 'high', 'low', 'close', 'adj_close', 'vol']
df = df.drop(['adj_close'], axis=1)  

records = df.to_records(index=False)
records = list(records)
cursor = connection.cursor()
query = "INSERT INTO " + table_name + " (date, open, high, low, close, volume) VALUES (%s, %s, %s, %s, %s, %s)"
cursor.executemany(query, records)
connection.commit()
connection.close()

Comments

-2

You can also import data into SQL by using either:

  • The SQL Server Import and Export Wizard
  • SQL Server Integration Services (SSIS)
  • The OPENROWSET function

More details can be found on this webpage: https://learn.microsoft.com/en-us/sql/relational-databases/import-export/import-data-from-excel-to-sql?view=sql-server-2017

1 Comment

I've been contemplating using SS to import data into DB than read it into Python. This comment seems to have drawn some negatives. It's from 2019, so maybe dated now. Guess I'll see. Thanks for comment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.