python 通过Python连接到SQL Server

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 通过Python连接到SQL Server相关的知识,希望对你有一定的参考价值。

########################################
### CONNECTING TO SQL SERVER USING pyodbc ###
########################################

# import pyodbc package
import pyodbc
# create conn object using the connect() method, variable holds the SQL Server connection information
conn = pyodbc.connect("Driver={SQL Server Native Client 11.0};"
                      "Server=DESKTOP-POJHB7A;"
                      "Database=scratch;"
                      # "username = User_Name;" # don't include if using Windows Authentication
                      # "password = User_Password;" # don't include if using Windows Authentication
                      "Trusted_Connection=yes;")

########################################
### SELECTING FROM SQL SERVER ###
########################################

# create cursor variable and use the cursor method
cursor = conn.cursor()
# SQL code is executed using the execute() method, and the results are placed into the cursor variable
# the SQL code is placed within single quotes like 'cursor.execute('SELECT * FROM table')', but you can use triple quotes to place in multi-line code
# setting NOCOUNT ON will make it so that any SQL Server error message encountered by the SQL statement will be passed to Python and will be visible as a DataError
cursor.execute('''  

    SET NOCOUNT ON; 

    SELECT a.*, b.price AS discount_price
    FROM products a
    JOIN productsdiscount b on a.productID = b.productID

    ''')

# print each row stored in cursor as selected from SQL Server
for row in cursor: 
    print(row)

'''
The values will be returned as tuples

(1, 2, 'guitar', Decimal('2.5000'), Decimal('2.5000'))
(2, 4, 'keyboard', Decimal('72.0000'), Decimal('72.0000'))
(3, 7, 'tuba', Decimal('9.2500'), Decimal('9.2500'))
(4, 8, 'drums', Decimal('33.0000'), Decimal('33.0000'))
(1002, 9, 'shaker', Decimal('14.2000'), Decimal('14.2000'))
(1003, 9, 'shaker', Decimal('14.2000'), Decimal('14.2000'))
(1004, 9, 'koto', Decimal('14.2000'), Decimal('14.2000'))

'''

########################################
### SELECTING FROM SQL SERVER INTO A DICTIONARY, INCLUDING COLUMN HEADERS ###
########################################

# create cursor variable and use the cursor method
cursor = conn.cursor()
cursor.execute('''  

    SET NOCOUNT ON; 

    SELECT * FROM products

    ''')

# Store cursor content's column names in a list variable. In cursor.description(), it'll return the properties of what is in the cursor
# in a tuple like '('ID', <class 'int'>, None, 10, 10, 0, False)', which includes the column header at index position [0]. Each column will
# be described in its own tuple. Therefore, accessing column[0] will select the column names.
# You can create a for loop which will go through the cursor tuples and grab all of the column names, 
# leaving you will a list that contains the column header values, like ['ID', 'productID', 'productname', 'price'].
columns = [column[0] for column in cursor.description]

# you can then create a list variable (results) that holds a list that holds a series of dictionaries. Using for loop and cursor.fetchall(), 
# you can use the append() method and zip, plugging in the columns variable and the for loop variable row.
results = []
for row in cursor.fetchall():
    results.append(dict(zip(columns, row)))

'''
If you then view the results variable, you'll now see that there is a list containing a series of dictionaries, one for each row. 
The column header will be placed as the key, and the value for that row will be placed in for value.

[{'ID': 1, 'productID': 2, 'productname': 'guitar', 'price': Decimal('3.2500')}, 
    {'ID': 2, 'productID': 4, 'productname': 'keyboard', 'price': Decimal('72.0000')}, 
    {'ID': 3, 'productID': 7, 'productname': 'tuba', 'price': Decimal('9.2500')}, 
    {'ID': 4, 'productID': 8, 'productname': 'drums', 'price': Decimal('33.0000')}, 
    {'ID': 1002, 'productID': 9, 'productname': 'shaker', 'price': Decimal('14.2000')}, 
    {'ID': 1003, 'productID': 9, 'productname': 'shaker', 'price': Decimal('14.2000')}, 
    {'ID': 1004, 'productID': 9, 'productname': 'koto', 'price': Decimal('14.2000')}, 
    {'ID': 1005, 'productID': 235, 'productname': 'synthesizer', 'price': Decimal('23.6300')}, 
    {'ID': 1006, 'productID': 664, 'productname': 'bells', 'price': Decimal('25.0000')}, 
    {'ID': 1007, 'productID': 666, 'productname': 'rhodes', 'price': Decimal('353.0000')}
    ]

'''

#######################################
### SELECTING FROM SQL SERVER WITH TRY BLOCK SO YOU CAN PRINT THE SQL SERVER ERROR THROWN ###
########################################

# create cursor variable and use the cursor method
cursor = conn.cursor()

try:
    cursor.execute('''  

    SET NOCOUNT ON; 

    -- generate a divide by zero error 
    SELECT 1 / 0

    ''')

    # print each row stored in cursor
    for row in cursor: 
        print(row)

except Exception as e: 
    print(e) # will print SQL Server error message

'''
Upon generating the error, the SQL Server error message will be stored in the exception e. If you print e, you'll be able to see
the display the SQL Server error in your Python application:

('22012', '[22012] [Microsoft][SQL Server Native Client 11.0][SQL Server]Divide by zero error encountered. (8134) (SQLExecDirectW)')
'''

#######################################
### SELECTING FROM SQL SERVER USING PARAMETERS INSTEAD OF VALUES IN THE SQL CODE ###
########################################

# This is safer as it helps guard against SQL injection, and is more efficient if the code is reused with different parameters.

# This statement has values inserted straight into the SQL:
cursor = conn.cursor()
cursor.execute("SELECT * FROM products where productID = 2 OR productname = 'drums'")

for row in cursor:
    print(row)

# However, you can use parameters instead:
cursor = conn.cursor()

# create variables to hold the values that you'll pass into the placeholders
productID = 2
productname = 'drums'

# you can pass ? as a placeholder, and then plug the values in at the end of cursor.execute() in the order they appear in the SQL code
cursor.execute("SELECT * FROM products where productID = ? OR productname = ?", productID, productname) 

for row in cursor:
    print(row)

# another example - note how to pass in a date value after importing the datetime module
cursor = conn.cursor()
cursor.execute("""
    select user_id, user_name
      from users
     where last_logon < ?
       and bill_overdue = ?
""", [datetime.date(2001, 1, 1), 'y'])

########################################
### INSERTING/UPDATING/DELETING DATA IN SQL SERVER USING DML ###
########################################

cursor = conn.cursor()
cursor.execute('''  
    UPDATE products
    SET price = 9.25
    WHERE productname = 'guitar'
    ''')
# this will create a TRANSACTION in SQL Server that must be committed when complete.
# If you don't commit, you'll lock the table in SQL Server making it unavailable to any other queries. 
conn.commit() 

# after inserting/updating/deleting rows, you can optionally check the rowcount of the cursor to see how many rows are there (i.e. how many were updated)
cursor.rowcount

# SELECT from SQL Server to see the change. Note double quotes are used in execute() since single quotes are used in the SQL code
cursor.execute("SELECT * FROM products WHERE productname = 'guitar'")

for row in cursor:
    print(row)

########################################
### INSERTING/UPDATING/DELETING DATA IN SQL SERVER USING DML FROM A PYTHON LIST ###
########################################

cursor = conn.cursor()

# create list variable with rows you'd like to insert as tuples
records_to_insert = [ (235,'synthesizer', 23.63),
                      (664,'bells', 25.00),
                      (666,'rhodes', 353.00) ]

# you can optionally create variable to hold the SQL statement, including placeholders for values that you'll be inserting
# the cursor will go through each tuple and fill in the placeholders and thereby insert the rows into the table
sql_insert_query = '''  
    INSERT INTO products (productID, productname, price)
    VALUES (?,?,?)
    '''
# use executemany() to INSERT the rows. The first argument is the variable holding the SQL code, and the second argument is the variable holding the tuples representing the rows to be inserted
cursor.executemany(sql_insert_query, records_to_insert)
# commit the transaction - if this isn't done, you'll lock the table
conn.commit()

# SELECT from SQL Server to see the change. Note double quotes are used in execute() since single quotes are used in the SQL code.
# Upon selecting the data, you'll see that each tuple will have been inserted as a row into the SQL Server table in the order of columsn
# that you inserted.
cursor.execute("SELECT * FROM products")

for row in cursor:
    print(row)

########################################
### INSERTING/UPDATING/DELETING DATA IN SQL SERVER USING DML FROM A PYTHON DICTIONARY ###
########################################

cursor = conn.cursor()

# create list variable with rows you'd like to insert as tuples
original_dictionary = [{'productID': 2, 'productname': 'guitar', 'price': 3.25}, 
                    {'productID': 4, 'productname': 'keyboard', 'price': 72.00}, 
                    {'productID': 7, 'productname': 'tuba', 'price': 9.25}] 

# convert dictionary values to tuples
dictionary_as_tuple_list = [tuple(value.values()) for value in original_dictionary]

# execute the SQL code using three placeholder values, specifying dictionary_as_tuple_list to be inserted for the placeholders
cursor.executemany("""
    INSERT INTO products (productID, productname, price)
    VALUES (?,?,?);

    """, dictionary_as_tuple_list)

# commit the transaction
conn.commit()

########################################
### OTHER CURSOR METHODS ###
########################################

# how to view the properies of what's currently in the cursor. Example output is: (('ID', <class 'int'>, None, 10, 10, 0, False), ('productID', <class 'int'>, None, 10, 10, 0, True), ('productname', <class 'str'>, None, 50, 50, 0, True), ('price', <class 'decimal.Decimal'>, None, 19, 19, 4, True))
cursor = conn.cursor()
cursor.execute('SELECT * FROM products')

cursor.description

# how to fetch what is in the cursor one row at a time.
# If this is run again, it'll fetch the next row. In this way, you can proceed one-by-one through the contents of the cursor.
# Once the cursor runs out of rows, it'll return None
cursor = conn.cursor()
cursor.execute('SELECT * FROM products')

cursor.fetchone() # will fetch first row of whatever is in the cursor
cursor.fetchone() # will fetch second row
cursor.fetchone() # will fetch third row...

# fetchmany() will fetch multiple rows at a time
cursor = conn.cursor()
cursor.execute('SELECT * FROM products')

cursor.fetchmany(3) # will fetch first three rows, as a list of tuples. Example output is [(1, 2, 'guitar', Decimal('9.2500')), (2, 4, 'keyboard', Decimal('72.0000')), (3, 7, 'tuba', Decimal('9.2500'))]
cursor.fetchmany(3) # will fetch the next three rows

# fetchall() will fetch all of the remaining rows from wherever the cursor is
cursor = conn.cursor()
cursor.execute('SELECT * FROM products')

cursor.fetchone() # will fetch first row
cursor.fetchall() # will fetch the rest of the rows. Since it's currently on row 2, it'll fetch rows 2 through the end


########################################
### EXAMPLE OF A PRODUCT SEARCH APPLICATION ###
########################################

# CONNECT TO THE SQL SERVER DATABASE HOLDING THE PRODUCTS TO BE SEARCHED
import pyodbc
conn = pyodbc.connect("Driver={SQL Server Native Client 11.0};"
                      "Server=DESKTOP-POJHB7A;"
                      "Database=scratch;"
                      # "username = User_Name;" # don't include if using Windows Authentication
                      # "password = User_Password;" # don't include if using Windows Authentication
                      "Trusted_Connection=yes;")

# ASK USER WHICH PRODUCT THEY WANT TO SEARCH FOR (WRAPPED IN TRY/EXCEPT BLOCKS TO HANDLE ANY INVALID INPUT)
# start a loop that asks for input until a valid entry is supplied
while True:
    try:
        user_input = str(input('Enter a product name to search: '))
        # if nothing is entered, return to top of loop and ask for input again
        if user_input == '':
            continue
    except ValueError:
        print('Sorry, I didn\'t understand that.')
        #not a valid input, go back to the beginning
        continue
    else:
        #valid input, exit the loop
        break

# DEFINE THE SQL QUERY TO USE FOR PRODUCT LOOKUP - ? IS THE WILCARD WHERE user_input WILL BE PLACED (THESE PARAMETERS APPARENTLY SANITIZE THE INPUT)
product_lookup_query = 'SELECT productname, price FROM products WHERE productname LIKE ?;'

# CREATE THE CURSOR
cursor = conn.cursor()

# EXECUTE SQL CODE AND RETURN RESULTS TO THE USER (WRAPPED IN TRY/EXCEPT BLOCKS TO HANDLE ANY SQL ERRORS THAT ARISE FROM THE INPUT)
try:
    # execute the code, with user_input having a % added to end for use in LIKE statement, so 'guitar' will become 'guitar%'
    cursor.execute(product_lookup_query, user_input + '%') 

    # print the results
    # if cursor.rowcount == 0 (an empty set), print 'NO RESULTS FOUND'
    if cursor.rowcount == 0: 
        print('NO RESULTS FOUND')
    # if cursor.rowcount != 0 (there's something there), print the results
    else:
        print('PRODUCTS FOUND:')
        for row in cursor: 
        # index 0 is productname column and index[1] is price column (cast as str since it'll come out of SQL Server as a decimal)
            print('Product: ' + row[0] + ', Price: ' + str(row[1]))

# if SQL code generates an error, notify the user
except Exception as e: 
    print('Database error. Please go back and try again.')

以上是关于python 通过Python连接到SQL Server的主要内容,如果未能解决你的问题,请参考以下文章

无法通过 Python 连接到 SQL Server

如何使用 Active Directory 集成身份验证通过 python SQL alchemy 连接到 Azure sql 数据库

使用Python通过Windows身份验证连接到MS SQL Server?

从 Python 连接到 SQL Server

不使用 ODBC 将 Python 连接到 SQL Server

使 Python 通过 SSH 隧道连接到 MySQL