Pythonは、過去5年間で爆発的に人気が高まっています。他のプログラミング言語に比べて学習曲線が緩やかなため、多くの新しいプログラマーがそれに惹かれています。経験豊富なプログラマーは、その拡張性とパワーのためにそれに惹かれます。ただし、この大量採用の主な推進要因の1つは、Pythonがデータベースを簡単に操作できることです。このPythonプログラミングチュートリアルでは、Pythonを使用してPython3を使用してSQLExpressと通信する方法を説明します。
Pythonとデータベースプログラミング
データベース機能をanyに統合したいPython初心者 anyで記述されたソフトウェアプロジェクト 言語には、少なくとも2の基本的な理解が必要です。 言語。 1つ目はもちろんPythonで、2つ目はデータベースで使用される特定の構造化照会言語(SQL)です。 SQLは標準化されていますが、実際には普遍的な言語ではありませんが、さまざまなデータベース間の実装は十分に近いため、データベースアプリケーション開発の経験が十分にあれば、あるデータベースから別のデータベースへの移動はそれほど難しくありません。
データベースに関するもう1つの重要な考慮事項は、すべてのデータベースに管理ソフトウェアが必要なことです。これらの管理ツールは、データベースへのアクセスとデータベース内のセキュリティ特権の設定を支援します。また、開発者が次のようなことを行えるようにするため、データベースアプリケーションのデバッグにも使用できます。
- テーブル、ビュー、およびその他のデータベースオブジェクトのコンテンツの作成と管理。これには、テーブル間の関係、および整合性ルールの構成が含まれます。
- SQLコードエントリを介したデータベースとの直接の対話。
- SQL構文のデバッグ。
- アプリケーションで誤ってコーディングされたSQLステートメントによって引き起こされた損傷を(ある程度)元に戻す。
開発者がMongoDBなどのnoSQLベースのデータベースを使用することを選択した場合でも、そのようなソリューションを機能させるために必要なデータベース固有のコーディング構文を学習することには課題があります。もちろん、これらは抑止力ではなく、ソフトウェア開発プロジェクトで考慮しなければならない技術的要因にすぎません。
Pythonおよびデータベースドライバー
Pythonは、他のプログラミング言語と同様に、特定のデータベースとネイティブに通信することはできません。特定のデータベースサーバー用に追加のモジュールを追加する必要があります。ベストプラクティスの観点からは、ソフトウェアプロジェクト用に選択されたデータベースサーバーに固有のデータベースドライバーモジュールを使用するのが最善です。そうすることで、モジュールに特定のプログラミング構文を使用するという追加コストが発生した場合でも、Pythonがデータベースサーバーのすべての機能にアクセスできるようになります。複数のデータベースサーバーに接続できる「ユニバーサル」データベースドライバーモジュールを作成する試みがいくつか行われていますが、これらは特定のデータベースサーバーの特定の機能へのアクセスを失うという犠牲を払って行われることがよくあります。
SQL Expressとは何ですか?
SQL Serverは、何十年もの間、Windowsの頼りになるデータベースサーバーソリューションでした。無料のデータベースサーバーソリューションからは程遠いものですが、Microsoftは、SQLExpressと呼ばれるSQLServerのゼロコストで簡素化されたバリアントを提供しています。 SQL Expressは、SQL Serverが使用するのと同じSQL構文をサポートしているため、初心者にとって理想的な学習ツールです。 SQLExpressとSQLServerはどちらも、「T-SQL」とも呼ばれる「Transact-SQL」と呼ばれるSQLのカスタム拡張機能を使用します。 SQLExpressとSQLServerはどちらも、アクセス管理のためのWindowsユーザーアカウントと従来のユーザー名およびパスワードシステムの使用をサポートしています。
Pythonは、 PyODBCという名前のモジュールを使用してSQLExpressまたはSQLServerと通信します。 。 SQLServerとSQLExpressはどちらも、一般に「SSMS」と呼ばれる「SQLServer管理システム」と呼ばれる別の無料のWindowsアプリケーションによって管理されます。この記事の執筆時点では、SQLExpressとSSMSはどちらもMicrosoftから個別にダウンロードされています。
- SSMSダウンロード
- SQLExpressのダウンロード
Python開発用にSQLExpressを構成する方法
SQL Expressは、SQL Serverと同様に、2種類の認証をサポートしています。 1つは、「信頼できる接続」とも呼ばれる、ユーザーのWindowsユーザーアカウントに基づく認証です。 2つ目は、従来のユーザー名とパスワードベースの認証が「混合モード認証」と呼ばれるもので実装されていることです。混合モード認証は、Windowsユーザーアカウントベースの認証とユーザー名およびパスワードベースの認証の両方をサポートします。 SQLServerまたはSQLExpressでは、ユーザー名とパスワードベースの認証を単独でサポートする方法はありません。
信頼できる接続を使用する主な利点の1つは、データベースの資格情報をアプリケーションコードに保存する必要がないことであるため、Microsoftは混合モード認証から移行しています。この記事のデモンストレーションもそれを使用しません。
インストール後に接続文字列をコピーしない
初心者レベルのアプリケーション開発者にとっての論点の1つは、SQLServer接続文字列を取り巻く最初の混乱です。 SQL Expressをインストールする場合、インストールプログラムは、作成されたSQLExpressインスタンスの接続文字列をインストール後に提供します。残念ながら、提供された接続文字列は PyODBCでは機能しない可能性があります 。この「景品」で安心感に「落ち着く」ことは魅力的ですが、それは価値以上の問題を引き起こすでしょう。
図1-SQLExpressインストーラーからの接続文字列の取得
この記事の執筆時点では、SQLExpressのインストールプログラムにはSSMSインストールプログラムをダウンロードするためのリンクも含まれていることに注意してください。
SQLExpressでデータベースを作成する方法
SQL ExpressとSSMSの両方をインストールしたら、適切なアクセス制限を備えた基本的なデータベースを作成します。 SSMSを開始する最も簡単な方法は、開始をクリックすることです。 Windowsのボタンをクリックし、検索バーに「ssms」と入力し、右上に「Microsoft SQL Server Management Studio 18」が表示されるのを待ってから、開くをクリックします。 [スタート]メニューパネルの右側にあるリンク:
図2–SSMSの開始
SSMSを起動すると、次のダイアログボックスが表示されます。
図3–SSMSオープニングダイアログ
Windows認証では、資格情報を入力する必要はありません。 Windowsユーザーアカウント SQL Expressがインストールされた場所には、SQLExpressインスタンスの管理者権限があります。 接続をクリックするだけです 続行します。
SSMSアプリケーションウィンドウの左端にあります 、オブジェクトエクスプローラーがあります 。新しいデータベースを作成するには、データベースを右クリックします データベースの作成を選択します コンテキストから メニュー:
図4–新しいデータベースの作成–パート1/2
新しいデータベース…をクリックします 新しいデータベースの詳細を入力できる新しいダイアログウィンドウが開きます。このデモンストレーションでは、データベースは RazorDemoと呼ばれます。 、C#でのRazorベースのアプリケーションの開発に関する以前の記事へのちょっとした逆戻りとして。 データベース名の横のテキストボックスにデータベースの名前を入力します 次に、 OKをクリックします ダイアログウィンドウの下部にあるボタン。次の図では、論理名の列に注意してください。 完全な論理名になるように、ファイルの一部がわずかに拡張されました 作成されているデータベースファイルの一部が公開されました:
図5–新しいデータベースの作成–パート2/2
新しいデータベースがオブジェクトエクスプローラーに表示されます データベースの下 フォルダ:
図6–新しく作成された「RazorDemo」データベース
SQLExpressでテーブルを作成する方法
リレーショナルデータベースは、データを格納するためのテーブルがないと実際には役に立ちません。これらのテーブルを作成する最も簡単な方法は、SQLコードを使用することです。 テーブル作成ウィザードを使用することもできますが、 テーブルを作成するには、SQLコードを使用する方が速く、簡単で、はるかに簡単です。 RazorDemoを右クリックして開始します データベースエントリを選択し、新しいクエリを左クリックします コンテキストウィンドウのオプション:
図7–新しいクエリウィンドウを開く
オブジェクトエクスプローラの右側に、次のようなクエリエディタウィンドウが表示されます。 :
図8–クエリエディタウィンドウ
テーブル作成コードを以下のリストに示します:
use RazorDemo; # See the Important Note below create table artists (rcdid int not null identity primary key, artist_name varchar(max)); create table albums (rcdid int not null identity primary key, artist_id int not null references artists(rcdid) on delete cascade, album_name varchar(max)); Listing 1 - Table Creation SQL Code
クエリエディタウィンドウを作成している間は注意してください 通常、データベースからは、選択したデータベースがコードの実行対象となることが保証されます。常に明示的に使用することをお勧めします。 コードの先頭にある目的のデータベース。 使用 コマンドは、それに続くデータベースの名前を明示的に選択します。
F5を押す または実行をクリックします ボタンはRazorDemoに対してステートメントを実行します データベース。実行が成功すると、「メッセージ」にその旨を示すメッセージが表示されます。 下のボックス:
図9–テーブル作成の成功
新しく作成されたテーブルとその列は、オブジェクトエクスプローラーで確認できます。 同じように。 更新する場合があることに注意してください データベース内の新しいオブジェクトを表示するには、データベースを右クリックしたときに表示されるコンテキストメニューのオプションを選択する必要がある場合があります。
図10–オブジェクトエクスプローラーの更新
図11–新しいテーブルとその列
この時点で、SSMSを安全に閉じることができます。
SSMSは、どのSQLServerデータベースでも同じように機能することに注意してください。使用されているデータベースサーバーに関係なく、すべてのテーブル作成コードを保存することが常にベストプラクティスです。 SQL ServerとSQLはそのようなスクリプトの回復を可能にしますが、どちらもそのようなステートメントでの暗号化の使用を可能にし、そのような場合、コードを回復することはできません。
PythonとSQLExpress
通常、ここではSQL Serverのセキュリティについて説明する必要がありますが、信頼できる接続 Pythonコードを実行する実行中のプロセスがWindowsユーザーによって所有されている限り、が使用されます アクセスされているデータベースにすでにアクセスできる場合、その議論は必要ありません。 SQLServerとSQLExpressはどちらも非常に堅牢なセキュリティ関連のカスタマイズを提供しますが、これらは初心者向けの記事の範囲を超えていることに注意してください。
実稼働環境で実行されているアプリケーションの適切なデータベースセキュリティを無視しないでください。投影環境でデータベースにアクセスするユーザーアカウントには、可能な限り最小限の権限のみが付与されていることを確認してください。
これらのコード例に使用されているPythonのバージョンは3.10であり、WindowsのMicrosoftストアからインストールされました。この方法でPythonをインストールすると、PythonおよびPIP3実行可能ファイルがシステムパスに追加されるため、これらのコマンドへのフルパスをコマンドプロンプトに入力する必要はありません。 ウィンドウズ。コード入力の場合、コストがかからない優れたテキストエディタはNotepad++です。
コマンドプロンプトウィンドウを開く
Pythonコードの実行は、コマンドプロンプトを介して行うのが最適です。 。 コマンドプロンプトにアクセスするには 、開始をクリックします Windowsのボタンをクリックし、 cmdと入力します 検索バーに。 コマンドプロンプトを待つ 表示してから開くをクリックします スタートメニューの右側にあるリンク :
図12–コマンドプロンプトを開く
典型的なコマンドプロンプト ウィンドウは次のようになります:
図13–一般的なコマンドプロンプト
PyODBCのインストール方法
PyODBC PythonがSQLServerとSQLExpressの両方にアクセスできるようにするPythonモジュールです。 MicrosoftストアからPythonをインストールすると、 PyODBC 次のコマンドでPythonに追加できます:
pip3 install pyodbc
図14–PyODBCの正常なインストール
Python2とPython3の両方など、Pythonの複数のバージョンがインストールされている場合は、 pip3のプレフィックスが必要になる場合があります。 適切なバージョンのPythonのコマンドへの完全なWindowsパスを使用したコマンド。
また、Python 3のみがインストールされている場合は、 pip3 コマンドは、より一般的な pipに対しても使用する必要があります これは適切な規則であるため、コマンド。
Pythonコードの記述
これでデータベースが構成され、 PyODBC インストールされると、データベースにデータを入力できます。アーティストとアルバムをカタログ化するデータベースの場合、ランダムに生成されたバンド名とアルバムで十分です。データベースに接続するためのPythonコードも含まれていますが、挿入は(まだ)含まれていません:
# bad-band-name-maker.py import sys import random import pyodbc part1 = ["The", "Uncooked", "Appealing", "Larger than Life", "Drooping", "Unwell", "Atrocious", "Glossy", "Barrage", "Unlawful"] part2 = ["Defeated", "Hi-Fi", "Extraterrestrial", "Adumbration", "Limpid", "Looptid", "Cromulent", "Unsettled", "Soot", "Twinkle"] part3 = ["Brain", "Segment", "Audio", "Legitimate Business", "Mentality", "Sound", "Canticle", "Monsoon", "Preserves", "Hangout"] part4 = ["Cougar", "Lion", "Lynx", "Ocelot", "Puma", "Jaguar", "Panther"] part5 = ["Fodder", "Ersatz Goods", "Leftovers", "Infant Formula", "Mush", "Smoothie", "Milkshakes"] def main(argv): # Connect to the RazorDemo database. conn = pyodbc.connect("Driver={ODBC Driver 17 for SQL Server};Server=localhost\SQLEXPRESS;Database=RazorDemo;Trusted_Connection=yes;") # Generate 15 bad band names: for x in range(1, 16): rand1 = random.randrange(0, 9) rand2 = random.randrange(0, 9) rand3 = random.randrange(0, 9) badName = part1[rand1] + ' ' + part2[rand2] + ' ' + part3[rand3] print ("Band name [" + str(x) + "] is [" + badName + "]") for y in range(1, 3): rand4 = random.randrange(0, len(part4)) rand5 = random.randrange(0, len(part5)) albumName = part4[rand4] + " " + part5[rand5] print ("\tAlbum [" + albumName + "]") # Close the Connection conn.close() return 0 if __name__ == "__main__": main(sys.argv[1:]) Listing 2 - Making up some data
これにより、次の出力が得られます。
図15–ランダムに生成されたバンド名
cdの使用に注意してください Pythonコードが保存されているディレクトリに移動するコマンド。 PyODBC connect() 現在ログインしているWindowsユーザーアカウントの場合、関数は失敗します SQLExpressでアクセスできるものとしてリストされていません。これは、データベースが1つのWindowsユーザーアカウントで作成されている場合にのみ問題になります。 ただし、コードは別のWindowsユーザーアカウントで実行されます 。
SQLおよびPyODBCにデータを挿入するための最悪の方法
多くの初心者のPython開発者は、 PyODBCを呼び出したくなります。 INSERTの呼び出し コードの次のセクションのステートメント、および次に説明する内容のコンテキストでは、これは悪い考えではありません。
図16–データベースを操作するための「ほぼ」間違った方法
PyODBCへの呼び出しを使用する理由 挿入を実行するには 、 SELECTs 、および UPDATEなどの他のデータベース関連機能 または削除 、ループ内は悪い場合があります。これは、これらの各呼び出しに伴うオーバーヘッドがあるためです。数百回、数千回、またはそれ以上の回数を繰り返す可能性のあるループ内では、スクリプトの実行にかなりの時間(分以上)が発生する可能性があります。このようなアプローチを使用するWebアプリケーションの場合、多くのWebサーバーがスクリプトの実行時間にハードキャップを課すため、パフォーマンスの問題はさらに悪化します。いかなる状況においても、ユーザーが作成した入力をデータベースに直接渡さないでください。常に入力をチェックして、データベース機能を壊したり、SQLインジェクション攻撃によってセキュリティ問題を引き起こしたりしないことを確認してください。
理想的には、上記のループを使用してSQLバッチ(ステートメントのリスト)を作成し、 PyODBCを作成することをお勧めします。 その単一のバッチで実行しますが、データがサニタイズされていない場合、これは非常に悪い考えです。
なぜデータをサニタイズする必要があるのでしょうか?ユーザー入力は決して信頼できないため、理由はセキュリティに要約されます。データをサニタイズするということは、プログラムの開発者が作成したSQLステートメント以外のものが実行されないようにデータを表現することを意味します。ユーザーは、任意に作成されたSQLコードの実行を可能にする悪意を持って作成された文字列を渡す可能性があります。これはSQLインジェクション攻撃として知られています。バッチに入るデータ値はサニタイズできますが、そのためのプロセスは入門チュートリアルの範囲を超えています。
PyODBC ユーザー入力をサニタイズすることにより、SQLインジェクション攻撃からデータベースを保護するためのメカニズムを提供します。これらには、パラメータ化されたステートメントの使用が含まれます 、プリペアドステートメントとも呼ばれます 。速度やその他のパフォーマンス指標が犠牲になったとしても、セキュリティは常に優先事項でなければなりません。
このデータベースにアクセスできるWindowsユーザーアカウントには、デフォルトでsysadmin権限があります。これは、SQLインジェクション攻撃が発生した場合、悪意のあるユーザーがサーバー上のすべてのデータベースのすべてのデータにアクセスできることを意味します。実際には、sysadmin権限を持つアカウントは、Pythonコードからデータベースにアクセスしてはなりません。
以下のリストは、 PyODBC を使用して、最初のPythonコード例を補強したものです。 データを挿入するためのカーソル:
# bad-band-name-maker2.py import sys import random import pyodbc part1 = ["The", "Uncooked", "Appealing", "Larger than Life", "Drooping", "Unwell", "Atrocious", "Glossy", "Barrage", "Unlawful"] part2 = ["Defeated", "Hi-Fi", "Extraterrestrial", "Adumbration", "Limpid", "Looptid", "Cromulent", "Unsettled", "Soot", "Twinkle"] part3 = ["Brain", "Segment", "Audio", "Legitimate Business", "Mentality", "Sound", "Canticle", "Monsoon", "Preserves", "Hangout"] part4 = ["Cougar", "Lion", "Lynx", "Ocelot", "Puma", "Jaguar", "Panther"] part5 = ["Fodder", "Ersatz Goods", "Leftovers", "Infant Formula", "Mush", "Smoothie", "Milkshakes"] def main(argv): # Connect to the RazorDemo database. conn = pyodbc.connect("Driver={ODBC Driver 17 for SQL Server};Server=localhost\SQLEXPRESS;Database=RazorDemo;Trusted_Connection=yes;") # Generate 15 bad band names, and try to keep them unique. previousNames = "" nameCount = 0 while (nameCount < 16): rand1 = random.randrange(0, 9) rand2 = random.randrange(0, 9) rand3 = random.randrange(0, 9) badName = part1[rand1] + ' ' + part2[rand2] + ' ' + part3[rand3] # A crude but effective way of ensuring uniqueness, although there is no unique constraint on the artist name in the database. # This prepends and appends bars to both the list of previously used names and the current name. If the current name is # new, it will not be in that string. if ("|" + previousNames + "|").find("|" + badName + "|") == -1: print ("Band name [" + str(nameCount) + "] is [" + badName + "]") sql1 = "insert into artists (artist_name) values (?)" values1 = [badName] rs1 = conn.cursor() rs1.execute(sql1, values1) rs1.commit() # If the cursor is not closed, then other cursors cannot be executed. rs1.close() for y in range(1, 3): rand4 = random.randrange(0, len(part4)) rand5 = random.randrange(0, len(part5)) albumName = part4[rand4] + " " + part5[rand5] print ("\tAlbum [" + albumName + "]") sql2 = "insert into albums (artist_id, album_name) values ((select top 1 rcdid from artists where artist_name=?), ?)" # Each array item here corresponds to the position of the ? in the SQL statement above. values2 = [badName, albumName] rs2 = conn.cursor () rs2.execute(sql2, values2) rs2.commit() rs2.close() # Creates a bar-delimited list of previously used names. if previousNames == "": previousNames = badName else: previousNames = previousNames + "|" + badName nameCount = 1 + nameCount else: print ("Found a duplicate of [" + badName + "]") #print (previousNames) # Close the Connection conn.close() return 0 if __name__ == "__main__": main(sys.argv[1:]) Listing 3 - Inserting the data
次のクエリをSSMSで実行して、コードの出力を確認できます。
図17–データの挿入の成功
SQLExpressおよびPythonでのデータの選択
データベースにデータがあるので、それをクエリするとよいでしょう。以下は、キーボードからユーザーデータを受け取り、パラメーター化されたクエリを介してデータベースに渡す簡単なスクリプトです。
# bad-band-name-maker3.py import sys import pyodbc def main(argv): searchValue = input("Enter something: ") # Cap the length at something reasonable. The first 20 characters. searchValue = searchValue[0:20] # Set the search value to lower case so we can perform case-insensitive matching: searchValue = searchValue.lower() # Connect to the RazorDemo database. conn = pyodbc.connect("Driver={ODBC Driver 17 for SQL Server};Server=localhost\SQLEXPRESS;Database=RazorDemo;Trusted_Connection=yes;") # You must use a parameterized query here in order to protect from SQL Injection Attacks! # For the like operator, the percent signs must be separated from the term or else the parameterization will fail. sql1 = ("select a.artist_name, b.album_name from artists a, albums b where b.artist_id = a.rcdid and " + "lower(album_name) like ('%' + ? + '%') order by a.artist_name, b.album_name") # Below is an array with one element: values1 = [searchValue] rs1 = conn.cursor() rs1.execute(sql1, values1) rows1 = rs1.fetchone() #print ("Type is [" + str(type(rows1)) + "]") if str(type(rows1)).find("NoneType") == -1: while rows1: # Columns are indexed by number only. 0 is the a.artist_name column and 1 is the b.album_name columns print(rows1[0] + " - " + rows1[1]) rows1 = rs1.fetchone() else: print ("No album name matched [" + searchValue + "]") # Close the Connection conn.close() return 0 if __name__ == "__main__": main(sys.argv[1:]) Listing 4 - Querying the Data
同じ結果。 1つには、大まかなSQLインジェクション攻撃の例も含まれています。
図18–クエリ結果。最後の検索値に注意してください。
Pythonデータベース開発に関する最終的な考え
Pythonを使用して開発できるSQLServer駆動型アプリケーションに制限はありません。開発者はSQLの知識によってのみ制限されます。この記事で紹介する基本的な概念が、SQLの理解を広げ、より複雑なアプリケーションを構築するという点で、初心者レベルの開発者を正しい方向に導くことができれば幸いです。
このPythonデータベースプログラミングチュートリアルでは、SQLExpressをSQLServerの開発用スタンドインとしてインストールする方法を紹介し、そのサーバー上のSQLExpressデータベースインスタンスと適切に通信するためにPython3を拡張する方法を示しました。この記事では、SQL ServerManagementStudioを使用してSQLExpressまたはSQLServerデータベースを管理する方法についても説明しました。さらに、この記事では、基本的なセキュリティ対策と、SQLServer駆動型アプリケーションの妥当な実行時間を確保するための効率的なコーディングの使用についても触れました。