【问题标题】:Cannot create database with SQLAlchemy with SQL Server无法使用 SQL Server 使用 SQLAlchemy 创建数据库
【发布时间】:2019-11-30 05:58:57
【问题描述】:

请注意,我一直在尝试使用 SQLAlchemy 创建一个新数据库,但在尝试使用 laravel 和 vagrant 时遇到了很多错误。谢天谢地,我已经能够使用 pyodbc 创建一个新数据库,但最终我想通过 SQLAlchemy 完成所有工作。

这是此时使用 pyodbc 创建新数据库的代码:

    for tagList in myTagList:
        conn = pyodbc.connect("driver={SQL Server Native Client 11.0};server=localhost,2433; database=master; UID=myUser;PWD=myUser2", autocommit=True) 
        conn.execute('CREATE DATABASE ' + tagList["job"].jobNumber)

如何更改它以使用 SQLAlchemy?目前,我查看了许多链接,例如 How to create a new database using SQLAlchemy?sqlalchemy,creating an sqlite database if it doesn't exist 但和 https://sqlalchemy-utils.readthedocs.io/en/latest/database_helpers.html 它似乎适用于 postgresql 但不适用于 SQL Server:

添加对创建数据库的支持(请参阅How to create a new database using SQLAlchemy?):

Projects>pip install sqlalchemy-utils
pip install sqlalchemy-utils
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won`t be maintained after that date. A future version of pip will drop support for Python 2.7. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support
Collecting sqlalchemy-utils
  Downloading https://files.pythonhosted.org/packages/bf/7e/3211ad9b3983b216d1b1863fd7734f80bacd1a62a5de8ff6844fb5ed1498/SQLAlchemy-Utils-0.35.0.tar.gz (129kB)
Requirement already satisfied: six in c:\users\myUser\appdata\roaming\python\python27\site-packages (from sqlalchemy-utils) (1.13.0)
Requirement already satisfied: SQLAlchemy>=1.0 in c:\python27\lib\site-packages (from sqlalchemy-utils) (1.3.11)
Installing collected packages: sqlalchemy-utils
    Running setup.py install for sqlalchemy-utils: started
    Running setup.py install for sqlalchemy-utils: finished with status 'done'
Successfully installed sqlalchemy-utils-0.35.0

--------------------------------------------------------------------------------

#Save historical data into new MyDB000N database
for tagList in myTagList:
    fsDatabaseEngine = create_engine('mssql+pyodbc://myUser:myUser2@localhost:2433/' + tagList["job"].jobNumber + '?driver=SQL+Server+Native+Client+11.0?trusted_connection=yes')
    if not database_exists(fsDatabaseEngine.url):
        create_database(fsDatabaseEngine.url)
    print(database_exists(fsDatabaseEngine.url))

-----

在这条线上if not database_exists(fsDatabaseEngine.url):接收:

    self.__connect(first_connect_check=True)
  File "C:\Python27\lib\site-packages\sqlalchemy\pool\base.py", line 639, in __connect
    connection = pool._invoke_creator(self)
  File "C:\Python27\lib\site-packages\sqlalchemy\engine\strategies.py", line 114, in connect
    return dialect.connect(*cargs, **cparams)
  File "C:\Python27\lib\site-packages\sqlalchemy\engine\default.py", line 482, in connect
    return self.dbapi.connect(*cargs, **cparams)
sqlalchemy.exc.InterfaceError: (pyodbc.InterfaceError) ('28000', u'[28000] [Microsoft][SQL Server Native Client 11.0][SQL Server]Login failed for user \'myUser\'. (18456) (SQLDriverConnect); [28000] [Microsoft][SQL Server Native Client 11.0][SQL Server]Cannot open database "MyDB00001" requested by the login. The login failed. (4060); [28000] [Microsoft][SQL Server Native Client 11.0][SQL Server]Login failed for user \'myUser\'. (18456); [28000] [Microsoft][SQL Server Native Client 11.0][SQL Server]Cannot open database "MyDB00001" requested by the login. The login failed. (4060)')
(Background on this error at: http://sqlalche.me/e/rvf5)

-----

C:\Python27\lib\site-packages\sqlalchemy\connectors\pyodbc.py:79: SAWarning: No driver name specified; this is expected by PyODBC when using DSN-less connections
  "No driver name specified; "

-----

#Save historical data into new MyDB000N database
for tagList in myTagList:
    # fsDatabaseEngine = create_engine('mssql://mssql@localhost:2433/' + tagList["job"].jobNumber + '?driver=SQL+Server+Native+Client+11.0?trusted_connection=yes')
    # if not database_exists(fsDatabaseEngine.url):
    create_database('mssql://mssql@localhost:2433/' + tagList["job"].jobNumber)
    #print(database_exists(fsDatabaseEngine.url))

  File "C:\Python27\lib\site-packages\sqlalchemy\engine\default.py", line 482, in connect
    return self.dbapi.connect(*cargs, **cparams)
sqlalchemy.exc.InterfaceError: (pyodbc.InterfaceError) ('IM002', u'[IM002] [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified (0) (SQLDriverConnect)')
(Background on this error at: http://sqlalche.me/e/rvf5)
PS Projects>

-----

#Save historical data into new MyDB000N database
for tagList in myTagList:
    # fsDatabaseEngine = create_engine('mssql://mssql@localhost:2433/' + tagList["job"].jobNumber + '?driver=SQL+Server+Native+Client+11.0?trusted_connection=yes')
    # if not database_exists(fsDatabaseEngine.url):
    create_database('mssql://myUser:myUser2@localhost:2433/' + tagList["job"].jobNumber+ '?driver=SQL+Server+Native+Client+11.0?trusted_connection=yes')
    #print(database_exists(fsDatabaseEngine.url))

  File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 1246, in _execute_context
    cursor, statement, parameters, context
  File "C:\Python27\lib\site-packages\sqlalchemy\engine\default.py", line 581, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.ProgrammingError: (pyodbc.ProgrammingError) ('42000', u'[42000] [Microsoft][SQL Server Native Client 11.0][SQL Server]CREATE DATABASE statement not allowed within multi-statement transaction. (226) (SQLExecDirectW)')
[SQL: CREATE DATABASE [MyDB00001]]
(Background on this error at: http://sqlalche.me/e/f405)
PS Projects>

-----

#Save historical data into new MyDB000N database
for tagList in myTagList:
    with create_engine(
        'mssql://mssql',
        isolation_level="AUTOCOMMIT"
        ).connect() as connection:
            connection.execute('CREATE DATABASE ' + tagList["job"].jobNumber)
    # if not database_exists(fsDatabaseEngine.url):
    #create_database('mssql://myUser:myUser2@localhost:2433/' + tagList["job"].jobNumber)
    #print(database_exists(fsDatabaseEngine.url))

  File "C:\Python27\lib\site-packages\sqlalchemy\engine\default.py", line 482, in connect
    return self.dbapi.connect(*cargs, **cparams)
sqlalchemy.exc.InterfaceError: (pyodbc.InterfaceError) ('IM002', u'[IM002] [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified (0) (SQLDriverConnect)')
(Background on this error at: http://sqlalche.me/e/rvf5)
PS Projects>

-----

#Save historical data into new MyDB000N database
for tagList in myTagList:
    session.execute('CREATE DATABASE ' + tagList["job"].jobNumber)

  File "C:\Python27\lib\site-packages\sqlalchemy\engine\default.py", line 581, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.ProgrammingError: (pyodbc.ProgrammingError) ('42000', u'[42000] [Microsoft][SQL Server Native Client 11.0][SQL Server]CREATE DATABASE statement not allowed within multi-statement transaction. (226) (SQLExecDirectW)')
[SQL: CREATE DATABASE MyDB00001]
(Background on this error at: http://sqlalche.me/e/f405)
PS Projects>

-----

#Save historical data into new MyDB000N database
for tagList in myTagList:
    conn = pyodbc.connect("driver={SQL Server};server=ubuntu-bionic; database=master; trusted_connection=true",
                      autocommit=True)

Exception has occurred: OperationalError
('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)')
  File "Projects\interesting_data.py", line 81, in <module>
    autocommit=True)

-----

#Save historical data into new MyDB000N database
for tagList in myTagList:
    conn = pyodbc.connect("driver={SQL Server Native Client 10.0};server=localhost,2433; database=master; trusted_connection=true", autocommit=True)

Exception has occurred: InterfaceError
('IM002', u'[IM002] [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified (0) (SQLDriverConnect)')
  File "Projects\interesting_data.py", line 80, in <module>
    conn = pyodbc.connect("driver={SQL Server Native Client 10.0};server=localhost,2433; database=master; trusted_connection=true", autocommit=True)

-----    

#Save historical data into new MyDB000N database
for tagList in myTagList:
    conn = pyodbc.connect("driver={SQL Server Native Client 11.0};server=localhost,2433; database=master; trusted_connection=true", autocommit=True)

Exception has occurred: OperationalError
('08001', u"[08001] [Microsoft][SQL Server Native Client 11.0]Invalid value specified for connection string attribute 'trusted_connection' (0) (SQLDriverConnect)")
  File "Projects\interesting_data.py", line 80, in <module>
    conn = pyodbc.connect("driver={SQL Server Native Client 11.0};server=localhost,2433; database=master; trusted_connection=true", autocommit=True)

-----

#Save historical data into new MyDB000N database
for tagList in myTagList:
    conn = pyodbc.connect("driver={SQL Server Native Client 11.0};server=localhost,2433; database=master; trusted_connection=yes", autocommit=True)

Exception has occurred: Error
('HY000', u'[HY000] [Microsoft][SQL Server Native Client 11.0]SQL Server Network Interfaces: No credentials are available in the security package\r\n (-2146893042) (SQLDriverConnect); [HY000] [Microsoft][SQL Server Native Client 11.0]Cannot generate SSPI context (-2146893042); [HY000] [Microsoft][SQL Server Native Client 11.0]SQL Server Network Interfaces: No credentials are available in the security package\r\n (-2146893042); [HY000] [Microsoft][SQL Server Native Client 11.0]Cannot generate SSPI context (-2146893042)')
  File "Projects\interesting_data.py", line 80, in <module>
    conn = pyodbc.connect("driver={SQL Server Native Client 11.0};server=localhost,2433; database=master; trusted_connection=yes", autocommit=True)

import urllib

#Save historical data into new MyDB000N database
for tagList in rdTagList:
    # if not database_exists(fsDatabaseEngine.url):
    params = urllib.parse.quote_plus("driver={SQL Server Native Client 11.0};server=localhost,2433; database=master; UID=phpUser;PWD=phpUser2")
    tagListEngine = sqlalchemy.create_engine("mssql+pyodbc:///?odbc_connect=%s" % params)
    tagListEngine.connect()

这给出了:

Exception has occurred: AttributeError
'module' object has no attribute 'parse'
  File "C:\Projects\interesting_data.py", line 82, in <module>
    params = urllib.parse.quote_plus("driver={SQL Server Native Client 11.0};server=localhost,2433; database=master; UID=myUser;PWD=myUser2")

你有什么建议? TIA。

更新:

不知道我以前是怎么错过它的,但最终基于@snakecharmerb 的建议,它现在可以在不需要urllib 的情况下工作:

#Save historical data into new MyDB000N database
for tagList in rdTagList:
    fsDatabaseEngine = create_engine('mssql+pyodbc://myUser:myUser2@localhost:2433/' + tagList["job"].jobNumber + '?driver=SQL+Server+Native+Client+11.0?trusted_connection=yes')
    if not database_exists(fsDatabaseEngine.url):
        create_database(fsDatabaseEngine.url)
    print(database_exists(fsDatabaseEngine.url))

谢谢!

更新 2:

在解决方案上归零,在我的研究中,我找到了使用 postgres://postgres 的解释 ...,但最终在我的情况下,我需要将 mssql://myUser 更改为 mssql+pyodbc://myUser...

【问题讨论】:

  • conn.execute('CREATE DATABASE ' + tagList["job"].jobNumber) 这句话真的可以注入。如果需要创建数据库,则应传递参数并使用带有QUOTENAME的动态语句:DECLARE @Create nvarchar(275); SET @Create = N'CREATE DATABASE ' + QUOTENAME(@Db) + N';'; EXEC sp_executesql @Create;
  • tagList["job"].jobNumber 是我从 python 脚本的其他地方得到的,所以我看不到它是如何对 SQL 注入开放的,因为这些是我从本地数据库。另外,您正在向我展示如何在 SQL 中解决注入问题,但在 python 中却没有,这没有帮助。
  • 如果你 print(fsDatabaseEngine.url) 是正确的连接字符串吗?错误消息表明登录凭据或数据库名称一定是错误的。
  • 好吧,我不知道我是怎么错过的——它现在突然起作用了!如果我打印 print(fsDatabaseEngine.url) 它会给我正确的连接字符串。如果您发布该@snakecharmerb,我会将其标记为答案。谢谢!
  • 有帮助的,@user8128167,因为诸如“CREATE DATABASE @Parameter;”之类的语法不是有效的语法,我假设你知道如何参数化 Python SQL 语句。你不安全地注入的事实说明我你不知道如何安全地注入。

标签: python sql-server sqlalchemy pyodbc


【解决方案1】:

根据@shakecharmerb的评论,解决方案如下:

#Save historical data into new MyDB000N database
for tagList in rdTagList:
    fsDatabaseEngine = create_engine('mssql+pyodbc://myUser:myUser2@localhost:2433/' + tagList["job"].jobNumber + '?driver=SQL+Server+Native+Client+11.0?trusted_connection=yes')
    if not database_exists(fsDatabaseEngine.url):
        create_database(fsDatabaseEngine.url)
    print(database_exists(fsDatabaseEngine.url))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-09
    • 2021-07-09
    • 2023-01-29
    • 2019-08-09
    • 1970-01-01
    • 2019-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多