Connecting to Azure SQL Server with AAD authentication using PyODBC - python

Environment:
Docker image: python:2.7.14-stretch (which means Debian 9 as underlying OS)
Installed SQL Server ODBC driver for Debian 9 (https://learn.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-2017)
using pyodbc module
Connecting to Azure SQL Server with AAD authentication.
Issue:
First connection to DB is made perfectly fine. However any next connection to same DB or other DB is failed with below error:
Exception::: ('08001', u'[08001] [unixODBC][Microsoft][ODBC Driver 17
for SQL Server]SSL Provider:
[error:140A90F1:lib(20):func(169):reason(241)] (-1)
(SQLDriverConnect)')
Cannot connect to DB
Please note that this is issue with only when using AAD autnethcation mode. If I use simple sql server user, everything runs fine.
Below is the example code snippet.
db_list = [TEST_DB1, TEST_DB2]
sql_conn = None
for db in db_list:
try:
conn_string = 'DRIVER={ODBC Driver 17 for SQL Server};' \
'SERVER=' + <db_url> + \
';DATABASE=' + <db_name> + \
';UID=' + <db_username> + \
';PWD=' + <db_password> + \
';Authentication=ActiveDirectoryPassword'
print conn_string
sql_conn = pyodbc.connect(conn_string)
except Exception as e:
print "Exception:::", e
print 'Cannot connect to DB' + str(sys.exc_info()[0])
return None
sql_conn.cursor().execute(<some SQL Query>)
sql_conn.close()

Related

How to do df.to_sql using SQL Server in Azure

I can do a df.to_slq on my local instance of SQL Server just fine. I am getting stuck when trying to do the same df.to_sll using Python and Azure SQL Server. I thought it would essentially be done like this.
import urllib.parse
params = urllib.parse.quote_plus(
'Driver=%s;' % '{ODBC Driver 17 for SQL Server}' +
'Server=%s,1433;' % 'ryan-server.database.windows.net' +
'Database=%s;' % 'ryan_sql_db' +
'Uid=%s;' % 'UN' +
'Pwd={%s};' % 'PW' +
'Encrypt=no;' +
'TrustServerCertificate=no;'
)
from sqlalchemy.engine import create_engine
conn_str = 'mssql+pyodbc:///?odbc_connect=' + params
engine = create_engine(conn_str)
connection = engine.connect()
connection
all_data.to_sql('health', engine, if_exists='append', chunksize=100000, method=None,index=False)
That is giving me this error.
OperationalError: (pyodbc.OperationalError) ('08S01', '[08S01] [Microsoft][ODBC Driver 17 for SQL Server]TCP Provider: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.\r\n (10060) (SQLExecDirectW); [08S01] [Microsoft][ODBC Driver 17 for SQL Server]Communication link failure (10060)')
[SQL: INSERT INTO health ([0], [Facility_BU_ID], [Code_Type], [Code], [Description], [UB_Revenue_Code], [UB_Revenue_Description], [Gross_Charge], [Cash_Charge], [Min_Negotiated_Rate], [Max_Negotiated_Rate], etc., etc., etc.
I found this link today:
https://learn.microsoft.com/en-us/sql/machine-learning/data-exploration/python-dataframe-sql-server?view=sql-server-ver15
I tried to do something similar, like this.
import pyodbc
import pandas as pd
df = all_data
# server = 'myserver,port' # to specify an alternate port
server = 'ryan-server.database.windows.net'
database = 'ryan_sql_db'
username = 'UN'
password = 'PW'
cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER='+server+';DATABASE='+database+';UID='+username+';PWD='+ password)
cursor = cnxn.cursor()
# Insert Dataframe into SQL Server:
for index, row in df.iterrows():
cursor.execute(all_data.to_sql('health', cnxn, if_exists='append', chunksize=100000, method=None,index=False))
cnxn.commit()
cursor.close()
When I run that, I get this error.
DatabaseError: Execution failed on sql 'SELECT name FROM sqlite_master WHERE type='table' AND name=?;': ('42S02', "[42S02] [Microsoft][ODBC SQL Server Driver][SQL Server]Invalid object name 'sqlite_master'. (208) (SQLExecDirectW); [42S02] [Microsoft][ODBC SQL Server Driver][SQL Server]Statement(s) could not be prepared. (8180)")
What I'm really hoping to to is df.to_sql, not Insert Into. I am working in Spyder and trying to send the data from my local machine to the cloud.
I read the two links below, and got it working.
https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-set-database-firewall-rule-azure-sql-database?view=azuresqldb-current
https://www.virtual-dba.com/blog/firewalls-database-level-azure-sql/
Basically, you need to open your command window on your local machine, enter 'ipconfig', and grab two IP addresses. Then, enter those into SQL Server in Azure.
EXECUTE sp_set_database_firewall_rule
N'health',
'192.0.1.1',
'192.0.0.5';
Finally, run the small script below, in SQL Server, to confirm that the changes were made correctly.
USE [ryan_sql_db]
GO
SELECT * FROM sys.database_firewall_rules
ORDER BY modify_date DESC

SQL Alchemy with SQL Server

I wasn't sure what to title my post, if you have a better idea, feel free to edit the title.
I have not used SQL Alchemy before and the documentation that I have looked at located in the following places, is not helpful:
Connecting to SQL Database Using SQL Alchemy in Python
Tutorial Point
Here is the code I am using:
import sqlalchemy as sal
from sqlalchemy import create_engine
#Here are the parameters I am using:
- server = 'Q-20/fake_example'
- database = 'AdventureWorks2017'
- driver = 'ODBC Driver 17 for SQL Server'
- trusted_connection='yes'
DATABASE_CONNECTION = 'mssql+pyodbc://#server = ' + server + '/database = ' + database + '?trusted_connection = ' + trusted_connection + '&driver=' + driver
engine = sal.create_engine(DATABASE_CONNECTION)
All of that seems to work fine without any problems; however, when I add this line:
connection=engine.connect()
I get the following error message:
sqlalchemy.exc.OperationalError: (pyodbc.OperationalError) ('08001',
'[08001] [Microsoft][ODBC Driver 17 for SQL Server]Named Pipes
Provider: Could not open a connection to SQL Server [53]. (53)
(SQLDriverConnect); [08001] [Microsoft][ODBC Driver 17 for SQL
Server]Login timeout expired (0); [08001] [Microsoft][ODBC Driver 17
for SQL Server]Invalid connection string attribute (0); [08001]
[Microsoft][ODBC Driver 17 for SQL Server]A network-related or
instance-specific error has occurred while establishing a connection
to SQL Server. Server is not found or not accessible. Check if
instance name is correct and if SQL Server is configured to allow
remote connections. For more information see SQL Server Books Online.
(53)')
I am not sure what is wrong with what I am doing, does anyone have any suggestions?
What I have tried so far:
I have confirmed that SQL Server is configured to allow remote connections. I did this check by following the instructions here
Removing the "#" sign before the server, but this just generated the same error message.
I figured out part of what I needed to do. I needed to change my parameters.
Old Parameters:
server = 'Q-20/fake_example'
database = 'AdventureWorks2017'
driver = 'ODBC Driver 17 for SQL Server'
trusted_connection='yes'
New Parameters:
server = 'Q-20'
database = 'AdventureWorks2017'
driver = 'SQL+SERVER+NATIVE+CLIENT+11.0'
trusted_connection='yes'
This is what my code ultimately looked like:
database_connection = 'mssql+pyodbc://Q-20/AdventureWorks2017?trusted_connection=yes&driver=SQL+SERVER+NATIVE+CLIENT+11.0'

How do I use pyodbc.connect() with authorization=ActiveDirectoryIntegrated?

Trying to access Azure SQL through a python function in VS code, with Authentication set to Active Directory Integrated. Using pyodbc to connect.
Works fine when run locally but get an error after deploying to Azure. Also works fine if I use SQL login but I want to use Active Directory Integrated. I have already set myself as an AD admin.
What I am trying:
cnxn = pyodbc.connect("Driver={ODBC Driver 17 for SQL Server};Server=tcp:khawajaserver1.database.windows.net,1433;Database=KhawajaDB1;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;Authentication=ActiveDirectoryIntegrated")
Error I get:
Result: Failure
Exception: Error: ('HY000', '[HY000] [Microsoft][ODBC Driver 17 for SQL Server]MAX_PROVS: Error code 0x57 (87) (SQLDriverConnect)')
Stack: File "/usr/local/lib/python3.6/site-packages/azure/functions_worker/dispatcher.py", line 308, in _handle__invocation_request
I know Active Directory Password as authentication type works.
db_list = [TEST_DB1, TEST_DB2]
sql_conn = None
for db in db_list:
try:
conn_string = 'DRIVER={ODBC Driver 17 for SQL Server};' \
'SERVER=' + <db_url> + \
';DATABASE=' + <db_name> + \
';UID=' + <db_username> + \
';PWD=' + <db_password> + \
';Authentication=ActiveDirectoryPassword'
print conn_string
sql_conn = pyodbc.connect(conn_string)
except Exception as e:
print "Exception:::", e
print 'Cannot connect to DB' + str(sys.exc_info()[0])
return None
sql_conn.cursor().execute(<some SQL Query>)
sql_conn.close()
when using the ODBC Driver 17 for SQL Server, the following works when you are using some form of Managed Identity to connect to an Azure SQL Instance;
conn_str = 'Driver={};SERVER=tcp:{},1433;DATABASE=CustomerProfiling;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;Authentication=ActiveDirectoryMsi;'.format("{ODBC Driver 17 for SQL Server}", os.environ["SQL_SERVER"])
conn = pyodbc.connect(conn_str)
The key is to use the ActiveDirectoryMsi Authentication attribute.
The following code worked for me
# Connection to SQL Server using AADIntegrated
import pyodbc
server = 'data1.database.windows.net'
database = 'MyTestDB'
authentication = 'ActiveDirectoryIntegrated'
kpi_server_connection = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER='+server+';DATABASE='+database+';Authentication='+authentication+';TrustServerCertificate='+ 'no')
query_string = '''
select top 10 * from [SomeTable]
'''
df = pd.read_sql(query_string, kpi_server_connection)
df

Connect to SQL Server Database using Pycharm (pyodbc)

I can access my SQL Server via SQL Server Mgmt Studio located at
<IP_ADDRESS> with credentials:
<USERID>
<PWD>
Using pycharm with Anaconda 2.7 as the interpreter my code is:
import pyodbc as p
server = '<IP_ADDRESS>'
database = 'listOfDBs/DB'
username = '<USERID>'
password = '<PWD>'
print ("DB CONNECT ATTEMPT")
try:
cnxn = p.connect(
'DRIVER={SQL Server};SERVER=' + server + ';DATABASE=' + database + ';UID=' + username + ';PWD=' + password)
print ("SUCCESS")
except Exception as e:
print ("Error: " + str(e))
My SQL Server is setup as:
ListOfDBs/DB
Folder1
Folder2
Folder3
Folder3
How do I connect to DB in ListOfDBs?
If I do:
Server = "XX.XXX.XXX/listOfDbs"
Database = "DB"
I get :
('08001', u'[08001] [Microsoft][ODBC SQL Server Driver][DBNETLIB]SQL Server does not exist or access denied. (17) (SQLDriverConnect); [08001] [Microsoft][ODBC SQL Server Driver][DBNETLIB]ConnectionOpen (Connect()). (53)')
If I do:
Server = "XX.XXX.XXX"
Database = "listOfDBs/DB"
I get:
('42000', u'[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Cannot open database "listOfDBs/DB" requested by the login. The login failed. (4060) (SQLDriverConnect); [42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Cannot open database "listOfDBs/DB" requested by the login. The login failed. (4060)')
How do I do this? I am using Pycharm community version.

Unable to connect pyODBC with SQL Server 2008 Express R2

I am using following code to connect with SQL 2008 R2:
cnxnStoneedge = pyodbc.connect("DRIVER={SQL Server};SERVER=127.0.0.1;DATABASE=myDB;UID=admin;PWD=admin")
Which gives error:
Error: ('08001', '[08001] [Microsoft][ODBC SQL Server Driver][DBNETLIB]SQL Server does not exist or access denied. (17) (SQLDriverConnect)')
args = ('08001', '[08001] [Microsoft][ODBC SQL Server Driver][DBNE...t exist or access denied. (17) (SQLDriverConnect)')
with_traceback = <built-in method with_traceback of Error object>
I am not sure whether SQL connecting via named Pipes or TCP, I did enable IP Address. Attaching Screen Shot
The following test code works for me to connect Python 2.7.5 with SQL Server 2008 R2 Express Edition:
# -*- coding: utf-8 -*-
import pyodbc
connStr = (
r'Driver={SQL Server};' +
r'Server=(local)\SQLEXPRESS;' +
r'Database=myDb;' +
r'Trusted_Connection=Yes;'
)
db = pyodbc.connect(connStr)
cursor1 = db.execute('SELECT [word] FROM [vocabulary] WHERE [ID]=5')
while 1:
row = cursor1.fetchone()
if not row:
break
print row.word
cursor1.close()
db.close()
and the following connection string also works for me because my \SQLEXPRESS instance is listening on port 52865:
connStr = (
r'Driver={SQL Server};' +
r'Server=127.0.0.1,52865;' +
r'Database=myDb;' +
r'Trusted_Connection=Yes;'
)

Categories

Resources