How to Connect Python to Microsoft SQL Server: Complete Guide

Microsoft SQL Server is a powerful relational database management system widely used in enterprise environments. Connecting Python to SQL Server allows developers to build robust data-driven applications combining Python's flexibility with SQL Server's enterprise features. This comprehensive guide covers everything you need to know about Python-SQL Server connectivity.

Why Use SQL Server with Python?

SQL Server combined with Python offers powerful capabilities:

  • Seamless integration with Microsoft ecosystem
  • Excellent Windows environment support
  • Advanced security and encryption features
  • High availability and disaster recovery
  • Powerful T-SQL language for complex operations
  • Integration Services (SSIS) for ETL
  • Analysis Services for business intelligence
  • Strong support for JSON and XML data

Prerequisites

Before connecting Python to SQL Server, ensure you have:

  • Python 3.6 or higher installed
  • SQL Server installed (Express, Standard, or Enterprise)
  • ODBC Driver for SQL Server installed
  • Database credentials (server, database, username, password)
  • Basic understanding of Python and T-SQL

Installing pyodbc

The most popular library for connecting Python to SQL Server is pyodbc:

bash

pip install pyodbc

Alternatively, you can use pymssql:

bash

pip install pymssql

We'll primarily use pyodbc as it's more feature-rich and widely adopted.

Installing SQL Server ODBC Driver

Download and install the Microsoft ODBC Driver for SQL Server from Microsoft's website. Check installed drivers:

python

import pyodbc

# List available ODBC drivers
drivers = pyodbc.drivers()
print("Available ODBC drivers:")
for driver in drivers:
    print(f"  - {driver}")

Basic Connection to SQL Server

Let's start with a simple connection:

python

import pyodbc

# Connection parameters
server = 'localhost'
database = 'TestDB'
username = 'sa'
password = 'YourPassword123'

# Create connection string
connection_string = f'DRIVER={{ODBC Driver 17 for SQL Server}};SERVER={server};DATABASE={database};UID={username};PWD={password}'

# Establish connection
connection = pyodbc.connect(connection_string)

print("Connected to SQL Server successfully!")

# Close connection
connection.close()

Windows Authentication

For Windows Authentication (trusted connection):

python

import pyodbc

server = 'localhost'
database = 'TestDB'

# Connection string for Windows Authentication
connection_string = f'DRIVER={{ODBC Driver 17 for SQL Server}};SERVER={server};DATABASE={database};Trusted_Connection=yes'

connection = pyodbc.connect(connection_string)

print("Connected using Windows Authentication!")

connection.close()

Connection with Error Handling

python

import pyodbc

def create_sql_connection():
    try:
        connection_string = (
            'DRIVER={ODBC Driver 17 for SQL Server};'
            'SERVER=localhost;'
            'DATABASE=TestDB;'
            'UID=sa;'
            'PWD=YourPassword123'
        )
        
        connection = pyodbc.connect(connection_string)
        
        print("Successfully connected to SQL Server")
        
        # Get SQL Server version
        cursor = connection.cursor()
        cursor.execute("SELECT @@VERSION")
        version = cursor.fetchone()[0]
        print(f"SQL Server version: {version[:50]}...")
        cursor.close()
        
        return connection
        
    except pyodbc.Error as e:
        print(f"Database error: {e}")
        return None
    except Exception as e:
        print(f"Error: {e}")
        return None

# Usage
conn = create_sql_connection()
if conn:
    conn.close()

Creating Tables

python

import pyodbc

connection = pyodbc.connect(
    'DRIVER={ODBC Driver 17 for SQL Server};'
    'SERVER=localhost;'
    'DATABASE=TestDB;'
    'UID=sa;'
    'PWD=YourPassword123'
)

cursor = connection.cursor()

# Create employees table
create_table_sql = """
CREATE TABLE employees (
    id INT IDENTITY(1,1) PRIMARY KEY,
    first_name NVARCHAR(50) NOT NULL,
    last_name NVARCHAR(50) NOT NULL,
    email NVARCHAR(100) UNIQUE,
    department NVARCHAR(50),
    salary DECIMAL(10, 2),
    hire_date DATE DEFAULT GETDATE()
)
"""

try:
    cursor.execute(create_table_sql)
    connection.commit()
    print("Table created successfully!")
except pyodbc.Error as e:
    print(f"Error creating table: {e}")

cursor.close()
connection.close()

Inserting Data

Insert Single Record

python

import pyodbc
from datetime import date

connection = pyodbc.connect(
    'DRIVER={ODBC Driver 17 for SQL Server};'
    'SERVER=localhost;'
    'DATABASE=TestDB;'
    'UID=sa;'
    'PWD=YourPassword123'
)

cursor = connection.cursor()

# Insert single employee
insert_sql = """
INSERT INTO employees (first_name, last_name, email, department, salary, hire_date)
VALUES (?, ?, ?, ?, ?, ?)
"""

employee_data = ('John', 'Doe', 'john.doe@company.com', 'Engineering', 75000.00, date.today())

cursor.execute(insert_sql, employee_data)
connection.commit()

# Get the inserted ID
cursor.execute("SELECT @@IDENTITY")
new_id = cursor.fetchone()[0]
print(f"Employee inserted with ID: {int(new_id)}")

cursor.close()
connection.close()

SQL Server uses ? as placeholders for parameterized queries.

Insert Multiple Records

python

import pyodbc

connection = pyodbc.connect(
    'DRIVER={ODBC Driver 17 for SQL Server};'
    'SERVER=localhost;'
    'DATABASE=TestDB;'
    'UID=sa;'
    'PWD=YourPassword123'
)

cursor = connection.cursor()

insert_sql = """
INSERT INTO employees (first_name, last_name, email, department, salary)
VALUES (?, ?, ?, ?, ?)
"""

employees_data = [
    ('Jane', 'Smith', 'jane@company.com', 'Marketing', 68000.00),
    ('Bob', 'Johnson', 'bob@company.com', 'Sales', 72000.00),
    ('Alice', 'Williams', 'alice@company.com', 'Engineering', 80000.00),
    ('Charlie', 'Brown', 'charlie@company.com', 'HR', 62000.00)
]

cursor.executemany(insert_sql, employees_data)
connection.commit()

print(f"{cursor.rowcount} employees inserted successfully!")

cursor.close()
connection.close()

Querying Data

Fetch All Records

python

import pyodbc

connection = pyodbc.connect(
    'DRIVER={ODBC Driver 17 for SQL Server};'
    'SERVER=localhost;'
    'DATABASE=TestDB;'
    'UID=sa;'
    'PWD=YourPassword123'
)

cursor = connection.cursor()

# Select all employees
select_sql = "SELECT id, first_name, last_name, department, salary FROM employees"
cursor.execute(select_sql)

rows = cursor.fetchall()

print(f"Total employees: {len(rows)}\n")

for row in rows:
    print(f"ID: {row.id}, Name: {row.first_name} {row.last_name}, Dept: {row.department}, Salary: ${row.salary}")

cursor.close()
connection.close()

Fetch with Conditions

python

import pyodbc

connection = pyodbc.connect(
    'DRIVER={ODBC Driver 17 for SQL Server};'
    'SERVER=localhost;'
    'DATABASE=TestDB;'
    'UID=sa;'
    'PWD=YourPassword123'
)

cursor = connection.cursor()

# Find employees in Engineering department
select_sql = "SELECT * FROM employees WHERE department = ?"
cursor.execute(select_sql, 'Engineering')

engineers = cursor.fetchall()

print("Engineering Department:")
for emp in engineers:
    print(f"{emp.first_name} {emp.last_name} - ${emp.salary}")

cursor.close()
connection.close()

Using Row Dictionary

python

import pyodbc

connection = pyodbc.connect(
    'DRIVER={ODBC Driver 17 for SQL Server};'
    'SERVER=localhost;'
    'DATABASE=TestDB;'
    'UID=sa;'
    'PWD=YourPassword123'
)

cursor = connection.cursor()

# Query with dictionary-like access
select_sql = "SELECT id, first_name, last_name, salary FROM employees WHERE salary > ?"
cursor.execute(select_sql, 70000)

# Get column names
columns = [column[0] for column in cursor.description]

# Create dictionaries
employees = []
for row in cursor.fetchall():
    employee = dict(zip(columns, row))
    employees.append(employee)

for emp in employees:
    print(f"{emp['first_name']} {emp['last_name']} - ${emp['salary']}")

cursor.close()
connection.close()

Updating Records

python

import pyodbc

connection = pyodbc.connect(
    'DRIVER={ODBC Driver 17 for SQL Server};'
    'SERVER=localhost;'
    'DATABASE=TestDB;'
    'UID=sa;'
    'PWD=YourPassword123'
)

cursor = connection.cursor()

# Update employee salary
update_sql = "UPDATE employees SET salary = ? WHERE id = ?"
cursor.execute(update_sql, 85000.00, 1)
connection.commit()

print(f"{cursor.rowcount} record(s) updated")

# Update multiple employees
update_sql = "UPDATE employees SET salary = salary * 1.10 WHERE department = ?"
cursor.execute(update_sql, 'Engineering')
connection.commit()

print(f"{cursor.rowcount} Engineering employees received raises")

cursor.close()
connection.close()

Deleting Records

python

import pyodbc

connection = pyodbc.connect(
    'DRIVER={ODBC Driver 17 for SQL Server};'
    'SERVER=localhost;'
    'DATABASE=TestDB;'
    'UID=sa;'
    'PWD=YourPassword123'
)

cursor = connection.cursor()

# Delete employee by ID
delete_sql = "DELETE FROM employees WHERE id = ?"
cursor.execute(delete_sql, 10)
connection.commit()

print(f"{cursor.rowcount} record(s) deleted")

cursor.close()
connection.close()

Working with Stored Procedures

python

import pyodbc

connection = pyodbc.connect(
    'DRIVER={ODBC Driver 17 for SQL Server};'
    'SERVER=localhost;'
    'DATABASE=TestDB;'
    'UID=sa;'
    'PWD=YourPassword123'
)

cursor = connection.cursor()

# Create stored procedure
proc_sql = """
CREATE PROCEDURE GetEmployeesByDepartment
    @DeptName NVARCHAR(50)
AS
BEGIN
    SELECT * FROM employees
    WHERE department = @DeptName
    ORDER BY last_name
END
"""

try:
    cursor.execute(proc_sql)
    connection.commit()
    print("Stored procedure created!")
except pyodbc.Error as e:
    print(f"Error: {e}")

# Call stored procedure
cursor.execute("EXEC GetEmployeesByDepartment ?", 'Engineering')

employees = cursor.fetchall()

print(f"Found {len(employees)} employees in Engineering")
for emp in employees:
    print(f"{emp.first_name} {emp.last_name}")

cursor.close()
connection.close()

Working with Output Parameters

python

import pyodbc

connection = pyodbc.connect(
    'DRIVER={ODBC Driver 17 for SQL Server};'
    'SERVER=localhost;'
    'DATABASE=TestDB;'
    'UID=sa;'
    'PWD=YourPassword123'
)

cursor = connection.cursor()

# Create procedure with output parameter
proc_sql = """
CREATE PROCEDURE GetEmployeeCount
    @DeptName NVARCHAR(50),
    @EmpCount INT OUTPUT
AS
BEGIN
    SELECT @EmpCount = COUNT(*)
    FROM employees
    WHERE department = @DeptName
END
"""

cursor.execute(proc_sql)
connection.commit()

# Call procedure with output parameter
dept = 'Engineering'
cursor.execute(f"DECLARE @count INT; EXEC GetEmployeeCount ?, @count OUTPUT; SELECT @count", dept)

count = cursor.fetchone()[0]
print(f"Employee count in {dept}: {count}")

cursor.close()
connection.close()

Working with Transactions

python

import pyodbc

connection = pyodbc.connect(
    'DRIVER={ODBC Driver 17 for SQL Server};'
    'SERVER=localhost;'
    'DATABASE=TestDB;'
    'UID=sa;'
    'PWD=YourPassword123'
)

cursor = connection.cursor()

try:
    # Start transaction
    cursor.execute("BEGIN TRANSACTION")
    
    cursor.execute("UPDATE employees SET salary = salary - 5000 WHERE id = 1")
    cursor.execute("UPDATE employees SET salary = salary + 5000 WHERE id = 2")
    
    # Commit transaction
    cursor.execute("COMMIT TRANSACTION")
    connection.commit()
    print("Transaction completed successfully")
    
except pyodbc.Error as e:
    # Rollback on error
    cursor.execute("ROLLBACK TRANSACTION")
    connection.commit()
    print(f"Transaction failed: {e}")
    
finally:
    cursor.close()
    connection.close()

Using Context Managers

python

import pyodbc
from contextlib import closing

def get_connection():
    return pyodbc.connect(
        'DRIVER={ODBC Driver 17 for SQL Server};'
        'SERVER=localhost;'
        'DATABASE=TestDB;'
        'UID=sa;'
        'PWD=YourPassword123'
    )

with closing(get_connection()) as conn:
    with closing(conn.cursor()) as cursor:
        cursor.execute("SELECT COUNT(*) FROM employees")
        count = cursor.fetchone()[0]
        print(f"Total employees: {count}")

Working with JSON Data

SQL Server has excellent JSON support:

python

import pyodbc
import json

connection = pyodbc.connect(
    'DRIVER={ODBC Driver 17 for SQL Server};'
    'SERVER=localhost;'
    'DATABASE=TestDB;'
    'UID=sa;'
    'PWD=YourPassword123'
)

cursor = connection.cursor()

# Create table with JSON column
cursor.execute("""
    CREATE TABLE user_settings (
        user_id INT PRIMARY KEY,
        settings NVARCHAR(MAX)
    )
""")

# Insert JSON data
settings = {
    "theme": "dark",
    "language": "en",
    "notifications": True
}

cursor.execute(
    "INSERT INTO user_settings (user_id, settings) VALUES (?, ?)",
    1, json.dumps(settings)
)
connection.commit()

# Query and parse JSON
cursor.execute("SELECT settings FROM user_settings WHERE user_id = 1")
result = cursor.fetchone()[0]
user_settings = json.loads(result)

print(f"User theme: {user_settings['theme']}")

# Query JSON using SQL Server JSON functions
cursor.execute("""
    SELECT JSON_VALUE(settings, '$.theme') as theme
    FROM user_settings
    WHERE user_id = 1
""")

theme = cursor.fetchone()[0]
print(f"Theme from JSON_VALUE: {theme}")

cursor.close()
connection.close()

Connection Pooling

python

import pyodbc

class ConnectionPool:
    def __init__(self, connection_string, pool_size=5):
        self.connection_string = connection_string
        self.pool = []
        self.pool_size = pool_size
        
        for _ in range(pool_size):
            self.pool.append(pyodbc.connect(connection_string))
    
    def get_connection(self):
        if self.pool:
            return self.

Subscribe to Transition from Excel to Python | Mito

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe