16. SGBD ve MySQL'in kullanımı

16.1. SGBD ve MySQL'in kurulumu
SGBD ve MySQL'e erişmek için Laragon yazılımını kuracağız.
16.1.1. Laragon'un kurulumu
Laragon, birkaç yazılımı bir araya getiren bir pakettir:
- bir Apache web sunucusu. Bunu Python ile web komut dosyaları yazmak için kullanacağız;
- SGBD ve MySQL;
- kullanmayacağımız PHP betik dili;
- web uygulamaları için önbellek işlevi gören bir Redis sunucusu. Bunu kullanmayacağız;
Laragon, Şubat 2020 itibarıyla şu adresten indirilebilir:


- [1-5] kurulumu, aşağıdaki dizin yapısını oluşturur:

- [6] içinde, PHP kurulum klasörü bulunur (bu belgede kullanılmamıştır);
[Laragon]'in başlatılmasıyla aşağıdaki pencere görüntülenir:

- [1]: Laragon'un ana menüsü;
- [2]: [Start All] düğmesi, Apache web sunucusunu ve SGBD ile MySQL'i başlatır;
- [3]: [WEB] düğmesi, [http://localhost] web sayfasını görüntüler;
- [4]: [Database] düğmesi, SGBD ve MySQL'i [phpMyAdmin] aracıyla yönetmenizi sağlar. Bunu önceden yüklemeniz gerekir;
- [5]: [Terminal] düğmesi bir komut terminalini açar;
- [6]: [Root] düğmesi, [http://localhost] web sitesinin kök dizini olan [<laragon>/www] klasörüne konumlandırılmış bir Windows Dosya Gezgini açar. Laragon’un Apache sunucusu tarafından yönetilen statik web uygulamaları buraya yerleştirilmelidir;
16.1.2. Veritabanı Oluşturma
Şimdi Laragon aracıyla bir veritabanı ve MySQL adlı bir kullanıcı hesabı oluşturmayı göstereceğiz.

- Laragon [1] başlatıldıktan sonra, [2] menüsünden yönetilebilir;
- [3-5]'te, henüz kurulmamışsa MySQL yönetim aracı [phpMyAdmin] kurulur;

- [6]'te, Apache web sunucusu ile SGBD ve MySQL başlatılır;
- [7] komutuyla Apache sunucusu başlatılır;
- [8] komutunda, SGBD ve MySQL komutları çalıştırılır;

- [8-10]'te, [dbpersonnes] ve [11] adında bir veritabanı oluşturulur. Kişiler veritabanı oluşturulacaktır;

- [11]'te, az önce oluşturduğumuz veritabanını yöneteceğiz;

- [Bases de données] işlemi, URL, [http://localhost/phpmyadmin] ve [12] adreslerine bir web isteği gönderir. Yanıtı Laragon’un Apache web sunucusu verir. URL ve [http://localhost/phpmyadmin], daha önce kurduğumuz [phpMyAdmin] yardımcı programının URL ve [5] bileşenleridir. Bu yardımcı program, MySQL veritabanlarını yönetmeye olanak tanır;
- varsayılan olarak, veritabanı yöneticisinin oturum açma bilgileri şunlardır: root [13], şifre yok [14];

- [16], daha önce oluşturduğumuz veritabanıdır;

- Şu anda [dbpersonnes], [17] ve boş olan [18] veritabanlarımız var;
[admpersonnes] adlı bir kullanıcı oluşturuyoruz; şifresi [nobody] olacak ve bu kullanıcı [dbpersonnes] veritabanında tüm haklara sahip olacak:

- [19] olarak, [dbpersonnes] veritabanında konumlandırılıyoruz;
- [20]'te, [Privileges] sekmesi seçilir;
- [21-22]'te, [root] kullanıcısının [dbpersonnes] veritabanı üzerinde tüm haklara sahip olduğu görülür;
- [23]'te yeni bir kullanıcı oluşturulur;

- [25-26]'te, kullanıcının kullanıcı adı [admdbpersonnes] olacaktır;
- [27-29]'te, şifresi [nobody] olacaktır;
- [30] durumunda, phpMyAdmin şifrenin çok zayıf (kırılması kolay) olduğunu belirtir. Üretim ortamında, [31] ile güçlü bir şifre oluşturmak tercih edilir;
- [32] değerinde, [admdbpersonnes] kullanıcısının [dbpersonnes] veritabanı üzerinde tüm haklara sahip olması gerektiği belirtilir;
- [33]'te, verilen bilgiler onaylanır;

- [35]'te, phpMyAdmin, kullanıcının oluşturulduğunu belirtir;
- [36]'te, veritabanında oluşturulan SQL emri;
- [37]'te, [admpersonnes] kullanıcısının [dbpersonnes] veritabanı üzerinde tüm haklara sahip olduğu belirtilir;
Artık elimizde şunlar var:
- MySQL ve [dbpersonnes] veritabanları;
- bu veritabanı üzerinde tüm haklara sahip bir [admpersonnes/nobody] kullanıcısı;
16.2. [mysql-connector-python] paketinin kurulumu
Daha önce oluşturulan veritabanını kullanmak için aşağıdaki mimariye sahip Python komut dosyaları yazacağız:

Bir konektör, Python kodunu kullanılan SGBD'ten ayırmaya yarar. Farklı SGBD'ler için konektörler mevcuttur ve bunlar aynı arayüzü kullanır. Ayrıca, yukarıda SGBD ve MySQL'i SGBD ve PostgreSQL ile değiştirdiğimizde, mimari şu şekilde olur:

SGBD'in tüm konektörleri aynı arayüze uyduğundan, Python betiğinin normalde değiştirilmesine gerek yoktur. Gerçekte, çoğu SGBD'in kendine ait bir SQL'i vardır:
- bu konektörler SQL (Yapısal Sorgu Dili) standardına uygundur;
- ancak bu standart tek başına yeterli olmadığından, özel dil uzantılarıyla genişletilir;
Bu nedenle, bir SGBD değişikliği sırasında komut dosyalarında SQL ile ilgili değişiklikler yapılması sıkça görülür.
Python, doğası gereği bir MySQL veritabanını yönetme olanağı sunmaz. Bunun için bir paket indirilmesi gerekir. Bu konuda birkaç seçenek mevcuttur. Burada, MySQL'in sahibi olan Oracle şirketinin resmi konektörü olan [mysql-connector-python] paketini kullanacağız.
Paketin kurulumu, Pycharm’daki bir [Terminal] penceresinde gerçekleştirilecektir:

- [2] klasörü, bundan sonra yapılacak işlemler açısından önemli değildir;
Terminalde [pip search MySQL] komutunu girin:
- [pip] (Python için Paket Yükleyici), Python paketlerini yüklemek için kullanılan araçtır. [pip] aracı, Python paketlerini içeren depoya bağlanır;
- [search MySQL]: adında [MySQL] terimini (büyük/küçük harf fark etmez) içeren paketlerin listesini ister;
Komutun sonuçları şöyledir:
mysql (0.0.2) - Virtual package for MySQL-python
jx-mysql (3.49.20042) - jx-mysql - JSON Expressions for MySQL
weibo-mysql (0.1) - insert mysql
bits-mysql (1.0.3) - BITS MySQL
MySQL-python (1.2.5) - Python interface to MySQL
deployfish-mysql (0.2.13) - Deployfish MySQL plugin
mtstat-mysql (0.7.3.3) - MySQL Plugins for mtstat
bottle-mysql (0.3.1) - MySQL integration for Bottle.
WintxDriver-MySQL (2.0.0-1) - MySQL support for Wintx
py-mysql (1.0) - Operating Mysql for Python.
mysql-utilities (1.4.3) - MySQL Utilities 1.4.3 (part of MySQL Workbench Distribution 6.0.0)
…. - Tool to move slices of data from one MySQL store to another
mysql-tracer (2.0.2) - A MySQL client to run queries, write execution reports and export results
mysql-utils (0.0.2) - A simple MySQL library including a set of utility APIs for Python database programming
mysql-connector-repackaged (0.3.1) - MySQL driver written in Python
dffml-source-mysql (0.0.5) - DFFML Source for MySQL Protocol
mysql-connector-python (8.0.19) - MySQL driver written in Python
INSTALLED: 8.0.19 (latest)
prometheus-mysql-exporter (0.2.0) - MySQL query Prometheus exporter
backwork-backup-mysql (0.3.0) - Backwork plug-in for MySQL backups.
django-mysql-manager (0.1.4) - django-mysql-manager is a Django based management interface for MySQL users and databases.
…. - mysql operate
C:\Data\st-2020\dev\python\cours-2020\v-01>
Adında veya açıklamasında MySQL anahtar kelimesi geçen tüm modüller listelenmiştir. Kullanacağımız modül (Şubat 2020), 17. satırdaki [mysql-connector-python]'tir. Bunu yüklemek için terminale [pip install -U mysql-connector-python] komutunu yazın:
C:\Data\st-2020\dev\python\cours-2020\v-01>pip install -U mysql-connector-python
Collecting mysql-connector-python
Using cached mysql_connector_python-8.0.19-py2.py3-none-any.whl (355 kB)
Requirement already satisfied, skipping upgrade: protobuf==3.6.1 in c:\myprograms\python38\lib\site-packages (from mysql-connector-python) (3.6.1)
Requirement already satisfied, skipping upgrade: dnspython==1.16.0 in c:\myprograms\python38\lib\site-packages (from mysql-connector-python) (1.16.0)
Requirement already satisfied, skipping upgrade: six>=1.9 in c:\users\serge\appdata\roaming\python\python38\site-packages (from protobuf==3.6.1->mysql-connector-python) (1.14.0)
Requirement already satisfied, skipping upgrade: setuptools in c:\myprograms\python38\lib\site-packages (from protobuf==3.6.1->mysql-connector-python) (41.2.0)
Installing collected packages: mysql-connector-python
Successfully installed mysql-connector-python-8.0.19
-
- satır: [install -U] seçeneği (U=yükseltme), [mysql-connector-python] paketiyle ilişkili çeşitli paketlerin en son sürümlerini ister;
Makinemizin Python ortamında yüklü olan paketleri öğrenmek için [pip list] komutunu girin:
C:\Data\st-2020\dev\python\cours-2020\v-01>pip list
Package Version
---------------------- ----------
asgiref 3.2.3
astroid 2.3.3
atomicwrites 1.3.0
attrs 19.3.0
certifi 2019.11.28
…
MarkupSafe 1.1.1
mccabe 0.6.1
more-itertools 8.1.0
mysql-connector-python 8.0.19
mysqlclient 1.4.6
packaging 20.0
pip 20.0.1
pipenv 2018.11.26
…
-
- satır: [mysql-connector-python] paketi gerçekten mevcut;
[mysql-connector-python] paketini kullanarak bir MySQL veritabanını yönetmeyi öğrenmek için |https://dev.mysql.com/doc/connector-python/en/| paketinin web sitesine gidin. Aşağıda bir dizi örnek sunulmaktadır.
16.3. [mysql_01] komut dosyası: MySQL veritabanına bağlanma - 1
[mysql_01] komut dosyası, bir veritabanını kullanmanın ilk adımını gösterir. Bu komut dosyası, daha önce oluşturulan [dbpersonnes] veritabanına bağlanabildiğimizi doğrulamamızı sağlayacaktır.
# mysql.connector modülünün içe aktarılması
from mysql.connector import connect, DatabaseError, InterfaceError
# bir veritabanına bağlanma MySql [dbpersonnes]
# kullanıcı kimliği (admpersonnes,nobody)
USER = "admpersonnes"
PWD = "nobody"
HOST = "localhost"
DATABASE = "dbpersonnes"
# başlıyoruz
connexion = None
try:
print("Connexion au SGBD MySQL en cours...")
# oturum açılıyor
connexion = connect(host=HOST, user=USER, password=PWD, database=DATABASE)
# izleme
print(
f"Connexion MySQL réussie à la base database={DATABASE}, host={HOST} sous l'identité user={USER}, passwd={PWD}")
except (InterfaceError, DatabaseError) as erreur:
# hata mesajı görüntüleniyor
print(f"L'erreur suivante s'est produite : {erreur}")
finally:
# bağlantı açıksa kapatılıyor
if connexion:
connexion.close()
Notlar
-
- satır: [mysql.connector] modülünden bazı işlevler ve sınıflar içe aktarılır;
- 6-7. satırlar: Bağlanacak kullanıcının kimlik bilgileri;
-
- satır: Veritabanını barındıran makine. MySQL konektörü, uzak bir veritabanıyla çalışmaya olanak tanır;
-
- satır: Bağlanılmak istenen veritabanının adı;
- 11-26. satırlar: komut dosyası, [admpersonnes / nobody] kullanıcısını [dbpersonnes] veritabanına bağlayacaktır (16. satır);
- 20-26. satırlar: Bağlantı başarısız olabilir. Bu nedenle, bağlantı işlemi bir try / except / finally bloğu içinde gerçekleştirilir;
-
- satır: [mysq.connector] modülünün connect yöntemi, farklı isimlendirilmiş parametreleri kabul eder:
- user: [admpersonnes] bağlantısının sahibi olan kullanıcı;
- password: [nobody] kullanıcısının şifresi;
- host: SGBD, MySQL ve [localhost] makineleri;
- database: Bağlanılacak veritabanı. İsteğe bağlı.
-
- satır: Bir istisna atılırsa, bu istisna [DatabaseError] veya [InterfaceError] türündedir;
- 23-26. satırlar: [finally] cümlesinde bağlantı kapatılır;
Sonuçlar
16.4. [mysql_02] komut dosyası: MySQL veritabanına bağlantı - 2
Bu yeni komut dosyasında, veritabanına bağlantı bir işlev içinde ayrılmıştır:
# mysql.connector modülünü içe aktarma
from mysql.connector import DatabaseError, InterfaceError, connect
# ---------------------------------------------------------------------------------
def connexion(host: str, database: str, login: str, pwd: str):
# [database] veritabanına bağlanır ve ardından bağlantıyı keser (kullanıcı adı, şifre) [host] sunucusundan
# sorun olması durumunda DatabaseError istisnasını tetikler
connexion = None
try:
# bağlantı
connexion = connect(host=host, user=login, password=pwd, database=database)
print(
f"Connexion réussie à la base database={database}, host={host} sous l'identité user={login}, passwd={pwd}")
finally:
# bağlantı açılmışsa kapatılır
if connexion:
connexion.close()
print("Déconnexion réussie\n")
# ---------------------------------------------- ana işlev
# giriş bilgileri
USER = "admpersonnes"
PASSWD = "nobody"
HOST = "localhost"
DATABASE = "dbpersonnes"
# mevcut bir kullanıcının oturumu
try:
connexion(host=HOST, login=USER, pwd=PASSWD, database=DATABASE)
except (InterfaceError, DatabaseError) as erreur:
# hata mesajı görüntüleniyor
print(erreur)
# mevcut olmayan bir kullanıcıya ait oturum açma
try:
connexion(host=HOST, login="xx", pwd="xx", database=DATABASE)
except (InterfaceError, DatabaseError) as erreur:
# hata mesajı görüntüleniyor
print(erreur)
Notlar:
- 6-19. satırlar: [connexion] işlevi, bir kullanıcıyı [dbpersonnes] veritabanına bağlamaya ve ardından bağlantıyı kesmeye çalışır. Sonucu görüntüler;
- 29-41. satırlar: ana program – connexion yöntemini iki kez çağırır ve olası istisnaları görüntüler;
Sonuçlar
16.5. [mysql_03] komut dosyası: MySQL tablosunun oluşturulması
Artık SGBD ve MySQL ile bağlantı kurmayı öğrendiğimize göre, bu bağlantı üzerinden SQL komutlarını vermeye başlayacağız. Bunun için, oluşturduğumuz [dbpersonnes] veritabanına bağlanacağız ve bu bağlantıyı kullanarak veritabanında bir tablo oluşturacağız.
# içe aktarmalar
import sys
from mysql.connector import DatabaseError, InterfaceError, connect
from mysql.connector.connection import MySQLConnection
# ---------------------------------------------------------------------------------
def execute_sql(connexion: MySQLConnection, update: str):
# bağlantı üzerinde bir güncelleme isteği yürütülüyor
curseur = None
try:
# bir imleç isteniyor
curseur = connexion.cursor()
# bağlantı üzerinde güncelleme sorgusu yürütülüyor
curseur.execute(update)
finally:
# imleç alınmışsa kapatılır
if curseur:
curseur.close()
# ---------------------------------------------- ana iş parçacığı
# bağlantı kimlik bilgileri
# kullanıcı kimliği
ID = "admpersonnes"
PWD = "nobody"
# veritabanı yönetim sisteminin ana bilgisayarı
HOST = "localhost"
# veritabanı kimliği
DATABASE = "dbpersonnes"
# adım adım ilerleyelim
try:
# bağlantı
connexion = connect(host=HOST, user=ID, password=PWD, database=DATABASE)
# AUTOCOMMIT modu
connexion.autocommit = True
except (InterfaceError, DatabaseError) as erreur:
# hatayı görüntülüyoruz
print(f"L'erreur suivante s'est produite : {erreur}")
# çıkış
sys.exit()
# "kişiler" tablosu varsa silinir
# Varsa bir hata oluşur - bu hata göz ardı edilir
requête = "drop table personnes"
try:
execute_sql(connexion, requête)
except (InterfaceError, DatabaseError):
pass
# "kişiler" tablosu oluşturulur
requête = "create table personnes (id int PRIMARY KEY, prenom varchar(30) NOT NULL, nom varchar(30) NOT NULL, age integer NOT NULL, " \
"unique(nom,prenom)) "
try:
# sorguyu çalıştır
execute_sql(connexion, requête)
# sonuçların görüntülenmesi
print(f"{requête} : requête réussie")
except (InterfaceError, DatabaseError) as erreur:
# hata görüntülenir
print(f"L'erreur suivante s'est produite : {erreur}")
finally:
# bağlantı kesiliyor
connexion.close()
Notlar:
-
- satır: execute_sql işlevi, açık bir bağlantı üzerinden SQL sorgusunu yürütür;
-
- satır: Bağlantı üzerindeki SQL işlemleri, imleç adı verilen özel bir nesne aracılığıyla gerçekleştirilir;
-
- satır: bir imleç alınır;
-
- satır: SQL sorgusunun yürütülmesi;
- satır 17-20: hata olsun ya da olmasın, imleç kapatılır. Bu, imleçle ilişkili kaynakları serbest bırakır. Bir istisna varsa, bu istisna burada işlenmez. İstisna, çağıran koda iletilir;
- satır 33-43: veritabanına bağlantı kurulur;
- satır 38: Bir bağlantı için AUTOCOMMIT=True modu, her sorgu çalıştırmasının otomatik bir işlem içinde gerçekleştirileceği anlamına gelir. Varsayılan mod AUTOCOMMIT=False'dir; bu durumda işlemleri yönetme sorumluluğu geliştiriciye aittir. İşlem, 1'den n'ye kadar birden fazla sorgunun yürütülmesini kapsayan bir mekanizmadır. Ya hepsi başarılı olur ya da hiçbiri başarılı olmaz. Dolayısıyla, 1'den i'ye kadar olan sorgular başarılı olurken i+1 numaralı sorgu başarısız olursa, veritabanının 1 numaralı sorgunun yürütülmesinden önceki durumuna geri dönmesi için 1'den i'ye kadar olan sorgular 'geri alınır';
- burada iki istek vardır: SQL (satır 49, 58). Her biri bir işlem içinde yürütülecektir. İkincisinin başarısız olması, birincisi üzerinde hiçbir etki yaratmaz;
- 45-51. satırlar: SQL [drop table personnes] emri yürütülür. Bu emir, [personnes] adlı tabloyu siler. Bu tablo mevcut değilse bir hata bildirilebilir. Bu hata göz ardı edilir (satır 51);
- 53-55. satırlar: [personnes] tablosunun oluşturulma komutu. Bir tablo, satır ve sütunlardan oluşan bir küme olarak görülebilir. Oluşturma komutu, sütunların adlarını belirtir:
- [id]: bir tamsayı tanımlayıcı. Bu, her kişi için benzersiz olacaktır. Bu, birincil anahtar olacaktır (PRIMARY KEY). Bu, tabloda bu sütunun aynı değeri iki kez almayacağı ve bir kişiyi tanımlamak için kullanılabileceği anlamına gelir;
- [nom]: en fazla 30 karakterden oluşan bir dize;
- [prenom]: en fazla 30 karakterden oluşan bir dize;
- [age]: bir tamsayı;
- Bu sütunların her biri için [NOT NULL] özniteliği, tablonun bir satırında bu üç sütundan hiçbirinin boş olamayacağı anlamına gelir;
- [unique(nom,prenom)] parametresi bir kısıtlama olarak adlandırılır. Burada satırlara uygulanan kısıtlama, satırdaki (soyadı, adı) tuple'ının tabloda benzersiz olması gerektiğidir. Bu, soyadı ve adı bilinen bir kişiyi tabloda benzersiz bir şekilde tanımlayabileceğimiz anlamına gelir;
- satır 56-60: SQL komutunun yürütülmesi;
- 61-63. satırlar: Olası istisnanın yönetimi;
- satır 64-66: veritabanından çıkış yapılır;
Sonuçlar
[phpMyAdmin] ile doğrulama:

- [dbpersonnes] [1] veritabanında, [personnes] [2] adlı bir tablo bulunur; bu tablonun yapısı [3-4]'tir, birincil anahtar [5] ve teklik kısıtlaması [6];
16.6. [mysql_04] komut dosyası: SQL komut dosyasının çalıştırılması
Daha önce [personnes] tablosunu oluşturduktan sonra, şimdi bu tabloyu doldurup SQL komutları yardımıyla işliyoruz.
Bir metin dosyasındaki SQL komutlarını çalıştırmak istiyoruz:

[commandes.sql] dosyasının içeriği şöyledir:
# [personnes] tablosunun silinmesi
drop table personnes
# kişiler tablosu oluşturuluyor
create table personnes (prenom varchar(30) not null, nom varchar(30) not null, age integer not null, primary key (nom,prenom))
# iki kişinin eklenmesi
insert into personnes(prenom, nom, age) values('Paul','Langevin',48)
insert into personnes(prenom, nom, age) values ('Sylvie','Lefur',70)
# tablonun görüntülenmesi
select prenom, nom, age from personnes
# kasıtlı hata
xx
# üç kişinin eklenmesi
insert into personnes(prenom, nom, age) values ('Pierre','Nicazou',35)
insert into personnes(prenom, nom, age) values ('Geraldine','Colou',26)
insert into personnes(prenom, nom, age) values ('Paulette','Girond',56)
# tablonun görüntülenmesi
select prenom, nom, age from personnes
# kişilerin soyadlarına göre alfabetik sırayla ve aynı soyadlıların ise adlarına göre alfabetik sırayla listelenmesi
select nom,prenom from personnes order by nom asc, prenom desc
# [20,40] aralığında yaşa sahip kişilerin listesi, yaşa göre azalan sırada
# ardından, yaşı eşit olanlar soyadlarına göre alfabetik sırayla ve soyadları eşit olanlar ise adlarına göre alfabetik sırayla listelenir
select nom,prenom,age from personnes where age between 20 and 40 order by age desc, nom asc, prenom asc
# Bayan Bruneau'nun listeye eklenmesi
insert into personnes(prenom, nom, age) values('Josette','Bruneau',46)
# yaşının güncellenmesi
update personnes set age=47 where nom='Bruneau'
# soyadı Bruneau olan kişilerin listesi
select nom,prenom,age from personnes where nom='Bruneau'
# Bayan Bruneau'nun silinmesi
delete from personnes where nom='Bruneau'
# soyadı Bruneau olan kişilerin listesi
select nom,prenom,age from personnes where nom='Bruneau'
Öncelikle, yeniden kullanabilmek için bir modüle yerleştireceğimiz işlevleri tanımlıyoruz:

[mysql_module] komut dosyası şu şekildedir:
# içe aktarmalar
from mysql.connector import DatabaseError, InterfaceError
from mysql.connector.connection import MySQLConnection
from mysql.connector.cursor import MySQLCursor
# ---------------------------------------------------------------------------------
def afficher_infos(curseur: MySQLCursor):
# bir SQL komutunun sonucunu görüntüler
…
# ---------------------------------------------------------------------------------
def execute_list_of_commands(connexion: MySQLConnection, sql_commands: list,
suivi: bool = False, arrêt: bool = True, with_transaction: bool = True):
# açık olan [connexion] bağlantısını kullanır
# bu bağlantı üzerinden [sql_commands] listesinde yer alan SQL komutlarını yürütür
# bu dosya, her satırda bir tane olmak üzere çalıştırılacak SQL komut dosyasıdır
# takip=True ise, her bir SQL komutunun yürütülmesi, komutun başarılı veya başarısız olduğunu belirten bir mesajın görüntülenmesiyle sonuçlanır
# durdurma=True ise, işlev karşılaşılan ilk hatada durur; aksi takdirde tüm SQL komutlarını yürütür
# eğer with_transaction=True ise, herhangi bir hata daha önce yürütülen tüm SQL komutlarını iptal eder
# eğer with_transaction=False ise, bir hata daha önce yürütülen SQL komutları üzerinde hiçbir etki yaratmaz
# işlev, bir [erreur1, erreur2, ...] listesi döndürür
….
# ---------------------------------------------------------------------------------
def execute_file_of_commands(connexion: MySQLConnection, sql_filename: str,
suivi: bool = False, arrêt: bool = True, with_transaction: bool = True):
# açık olan [connexion] bağlantısını kullanır
# bu bağlantı üzerinden sql_filename metin dosyasında bulunan SQL komutlarını yürütür
# bu dosya, her satırda bir tane olmak üzere çalıştırılacak SQL komut dosyasıdır
# eğer takip=True ise, her bir SQL komutunun yürütülmesi, komutun başarılı olup olmadığını belirten bir mesajın görüntülenmesiyle sonuçlanır
# durdurma=True ise, işlev karşılaşılan ilk hatada durur; aksi takdirde tüm SQL komutlarını yürütür
# eğer with_transaction=True ise, herhangi bir hata daha önce yürütülen tüm SQL komutlarını iptal eder
# eğer with_transaction=False ise, bir hata daha önce yürütülen SQL komutları üzerinde hiçbir etki yaratmaz
# işlev, bir [erreur1, erreur2, ...] listesi döndürür
# SQL dosyasının işlenmesi
try:
# dosyanın okuma modunda açılması
file = open(sql_filename, "r")
# işleme
return execute_list_of_commands(connexion, file.readlines(), suivi, arrêt, with_transaction)
except BaseException as erreur:
# bir hata tablosu döndürülür
return [f"Le fichier {sql_filename} n'a pu être être exploité : {erreur}"]
Notlar:
-
- satır: [execute_file_of_commands] işlevi, [sql_filename] adlı metin dosyasında bulunan SQL komutlarını yürütür:
- parametrelerin anlamlarını öğrenmek için 31-38. satırlardaki açıklamalara bakınız;
- 40-48. satırlar: [sql_filename] adlı metin dosyası işlenir;
-
- satır: dosyanın açılması;
-
- satır: [execute_list_of_commands] işlevi çalıştırılır; bu işlev, kendisine bir liste halinde aktarılan SQL komutlarını yürütür. Bu liste, burada [file.readlines()] metin dosyasının tüm satırlarından oluşan listeden oluşur (45. satır);
[execute_list_of_commands] işlevi şu şekildedir:
# ---------------------------------------------------------------------------------
def execute_list_of_commands(connexion: MySQLConnection, sql_commands: list,
suivi: bool = False, arrêt: bool = True, with_transaction: bool = True):
# açık bağlantıyı kullanır [connexion]
# bu bağlantı üzerinden [sql_commands] listesinde yer alan SQL komutlarını yürütür
# bu dosya, her satırda bir tane olmak üzere çalıştırılacak SQL komut dosyasıdır
# takip=True ise, her bir SQL komutunun yürütülmesi, komutun başarılı veya başarısız olduğunu belirten bir mesajın görüntülenmesiyle sonuçlanır
# durdurma=True ise, işlev karşılaşılan ilk hatada durur; aksi takdirde tüm SQL komutlarını yürütür
# eğer with_transaction=True ise, herhangi bir hata daha önce yürütülen tüm SQL komutlarını iptal eder
# eğer with_transaction=False ise, bir hata daha önce yürütülen SQL komutları üzerinde hiçbir etki yaratmaz
# işlev, bir [erreur1, erreur2, ...] listesi döndürür
# başlatma işlemleri
curseur = None
connexion.autocommit = not with_transaction
erreurs = []
try:
# bir kaydırıcı isteniyor
curseur = connexion.cursor()
# sql_commands içinde bulunan sql_commands ve SQL komutlarının yürütülmesi
# bunlar tek tek çalıştırılıyor
for command in sql_commands:
# geçerli komutun başındaki ve sonundaki boşluklar kaldırılır
command = command.strip()
# boş bir komut mu yoksa bir yorum mu var? Varsa, bir sonraki komuta geçilir
if command == '' or command[0] == "#":
continue
# geçerli komutun yürütülmesi
error = None
try:
curseur.execute(command)
except (InterfaceError, DatabaseError) as erreur:
error = erreur
# Bir hata oluştu mu?
if error:
# bir hata daha
msg = f"{command} : Erreur ({error})"
erreurs.append(msg)
# Ekran izleme var mı, yok mu?
if suivi:
print(msg)
# durdurulacak mı?
if with_transaction or arrêt:
# hata listesini gösterelim mi?
return erreurs
else:
# hata yok
if suivi:
print(f"[{command}] : Exécution réussie")
# komutun sonucunu göster
afficher_infos(curseur)
# hata tablosunu döndürüyor
return erreurs
finally:
# imleci kapatır
if curseur:
curseur.close()
# işlem varsa onaylanır / iptal edilir
if with_transaction:
if erreurs:
# iptal
connexion.rollback()
else:
# onaylama
connexion.commit()
Notlar
-
- satır: [execute_list_of_commands] işlevi, [sql_commands] listesinde bulunan SQL komutlarını yürütür:
- parametrelerin anlamını öğrenmek için 4-11. satırlardaki açıklamalara bakınız;
-
- satır: Alınan bağlantı, bir veritabanına açık bir bağlantıdır;
-
- satır: [sql_commands] listesindeki tüm komutların bir işlem içinde yürütülmesini istiyorsanız, AUTOCOMMIT=False modunda çalışmanız gerekir. Aksi takdirde, AUTOCOMMIT=True modunda çalışılır ve bu durumda [sqlCommands] listesindeki her bir komut otomatik bir işlem içinde yürütülür ve genel bir işlem olmaz;
-
- satır: Çeşitli SQL komutlarını yürütmek için bir imleç talep edilir;
- 22-51. satırlar: komutlar tek tek yürütülür;
- 26-27. satırlar: SQL komut listesindeki boş satırlar ve yorumlar kabul edilir. Bu durumda komut basitçe göz ardı edilir;
- satır 30-33: mevcut sorgu yürütülür;
- satır 35-45: mevcut sorgunun yürütülmesi sırasında oluşabilecek bir hata durumu işlenir;
- satır 37-38: hata, hata tablosuna eklenir;
- satır 40-41: izleme istenmişse, hata mesajı görüntülenir;
- satır 43-45: çağıran kod, ilk hatadan sonra durmayı talep etmişse veya bir işlem kullanılması talep edilmişse, durulmalıdır. Hata tablosu döndürülür;
- satır 46-51: mevcut sorgunun yürütülmesinde hata olmaması durumu;
- satır 48-49: izleme istenmişse, yürütülen sorgu “başarılı” ibaresiyle birlikte görüntülenir;
- satır 50-51: Yürütülen sorgunun sonucu görüntülenir. [afficher_infos] işlevine biraz ileride tekrar değineceğiz;
- satır 54-65: [finally] cümlesi, istisna olsun ya da olmasın her durumda yürütülür;
- satır 56-57: imleç kapatılır. Bu, imlece ayrılmış kaynakları serbest bırakır;
- satır 59-65: çağıran kodun SQL komutlarının bir işlem içinde yürütülmesini talep ettiği durum işlenir;
-
- satır: [erreurs] listesinin boş olup olmadığına bakılır; bu, herhangi bir istisna oluşmadığı anlamına gelir. Bu durumda işlem onaylanır (65. satır), aksi takdirde iptal edilir (62. satır);
[afficher_infos] işlevi bir sorgunun sonucunu görüntüler:
# ---------------------------------------------------------------------------------
def afficher_infos(curseur: MySQLCursor):
print(type(curseur))
# bir SQL komutunun sonucunu görüntüler
# Bu bir SELECT komutu muydu?
if curseur.description:
# imlecin bir açıklaması var - yani bir SELECT komutu çalıştırılmış
# description[i], SELECT sorgusundaki i numaralı sütunun açıklamasıdır
# descriptionQZXW2HTMLBW2ldZQXQZXW2HTMLBWzBdZQX, select sorgusundaki i numaralı sütunun adıdır
# alan adları görüntülenir
titre = ""
for i in range(len(curseur.description)):
titre += curseur.description[i][0] + ", "
# alan listesi son virgül olmadan görüntülenir
print(titre[0:len(titre) - 1])
# ayırıcı satır
print("*" * (len(titre) - 1))
# seçim tablosunun geçerli satırı
ligne = curseur.fetchone()
while ligne:
# görüntülenir
print(ligne)
# seçim listesinin bir sonraki satırı
ligne = curseur.fetchone()
# ayırıcı satır
print("*" * (len(titre) - 1))
else:
# imlecin alanı yok [description] - dolayısıyla bir komut çalıştırdı SQL
# güncelleme (ekleme, silme, güncelleme) komutunu çalıştırdı
print(f"nombre de lignes modifiées : {curseur.rowcount}")
Notlar
-
- satır: İşlevin parametresi, az önce bir SQL komutunu çalıştıran imleçtir. Bu komutun bir SELECT komutu mu, yoksa bir INSERT, UPDATE, DELETE güncelleme komutu mu olduğuna bağlı olarak, imlecin içeriği farklıdır;
-
- satır: Eğer imleç [description] alanına sahipse, o zaman bir SELECT komutunu yürütmüştür ve [description], SELECT'te talep edilen alanları tanımlar:
- description[i], SELECT tarafından istenen i numaralı alanı tanımlar. Bu bir listedir;
- description[i][0], i numaralı alanın adıdır;
- satır 11-17: SELECT tarafından istenen alanların adları görüntülenir;
- satır 18-24: SELECT'in sonucu işlenir;
-
- ve 24. satırlar: SELECT'in sonucu sırayla işlenir. Bu sonuç bir satır kümesidir. Geçerli satır, [curseur.fetchone()] (19. satır) ile elde edilir. Böylece bir tuple elde edilir;
- 27-30. satırlar: eğer imleç [description] alanına sahip değilse, o zaman INSERT, UPDATE, DELETE güncelleme komutlarını yürütmüştür. Böylece, bu komutun yürütülmesiyle tablodaki kaç satırın değiştirildiğini öğrenebiliriz;
-
- satır: [curseur.rowcount] bu sayıdır;
Ana komut dosyası [mysql-04], az önce açıkladığımız [mysql_module] modülünü kullanır:

[config_04] dosyası, [mysql_04] komut dosyasının yürütme ortamını yapılandırır:
def configure():
import os
# yapılandırma dosyasının bulunduğu klasörün mutlak yolu
script_dir = os.path.dirname(os.path.abspath(__file__))
# syspath klasörlerinin yapılandırması
absolute_dependencies = [
# yerel klasörler
f"{script_dir}/shared",
]
# syspath'ın sabitlenmesi
from myutils import set_syspath
set_syspath(absolute_dependencies)
# yapılandırmayı geri yükleme
return {
# komut dosyası SQL
"commands_filename": f"{script_dir}/data/commandes.sql",
# veritabanı bağlantı kimlik bilgileri
"host": "localhost",
"database": "dbpersonnes",
"user": "admpersonnes",
"password": "nobody"
}
[mysql_04] komut dosyası şöyledir:
# uygulama yapılandırmasını alıyoruz
import config_04
config = config_04.configure()
# syspath yapılandırıldı - içe aktarmalar yapılabilir
import sys
from mysql_module import execute_file_of_commands
from mysql.connector import connect, DatabaseError, InterfaceError
# ---------------------------------------------- ana işlev
# çağrı sözdiziminin doğrulanması
# argv[0] true / false
args = sys.argv
erreur = len(args) != 2
if not erreur:
with_transaction = args[1].lower()
erreur = with_transaction != "true" and with_transaction != "false"
# hata mı?
if erreur:
print(f"syntaxe : {args[0]} true / false")
sys.exit()
# metin hesaplama
with_transaction = with_transaction == "true"
if with_transaction:
texte = "avec transaction"
else:
texte = "sans transaction"
# ekran günlükleri
print("--------------------------------------------------------------------")
print(f"Exécution du fichier SQL {config['commands_filename']} {texte}")
print("--------------------------------------------------------------------")
# dosyadaki SQL komutlarının yürütülmesi
connexion = None
try:
# veritabanına bağlantı
connexion = connect(host=config['host'], user=config['user'], password=config['password'],
database=config['database'])
# SQL komut dosyasının çalıştırılması
erreurs = execute_file_of_commands(connexion, config["commands_filename"], suivi=True, arrêt=False,
with_transaction=with_transaction)
except (InterfaceError, DatabaseError) as erreur:
# hatanın görüntülenmesi
print(f"L'erreur fatale suivante s'est produite : {erreur}")
# işlem sonlandırılıyor
sys.exit()
finally:
# bağlantı açıksa kapatma
if connexion:
connexion.close()
# hata sayısının görüntülenmesi
print("--------------------------------------------------------------------")
print(f"Exécution terminée")
print("--------------------------------------------------------------------")
print(f"Il y a eu {len(erreurs)} erreur(s)")
# hataların görüntülenmesi
for erreur in erreurs:
print(erreur)
Notlar
- 1-4. satırlar: komut dosyasının yapılandırılması;
-
- satır: daha önce açıklanan [mysql_module] modülünün içe aktarılması:
- 12-22. satırlar: [mysql-04] komut dosyası, [true / false] değerlerinden birine sahip olması gereken bir parametre bekler. Bu parametre, SQL komut dosyasının bir işlem içinde (true) mı yoksa dışında (false) mı çalıştırılacağını belirtir;
-
- satır: Kullanıcı tarafından komut dosyasına aktarılan parametreler, [sys.argv] listesinde bulunur;
- satır 15: iki parametre gereklidir, örneğin [mysql-04 true]. Komut dosyasının adı bir parametre olarak sayılır;
- satır 17-18: Eğer iki parametre varsa, ikincisinin 'true' veya 'false' değerinde bir karakter dizisi olması gerekir;
- 24-29. satırlar: 33. satırda görüntülenecek metnin hesaplanması;
- satır 39-44: [./data/commandes.sql] dosyasındaki komutlar yürütülür;
- satır 45-49: Bağlantı sırasında (satır 40) bir hata oluşursa veya [execute_file_of_commands] betiği tarafından işlenemeyen bir hata olursa, hata mesajı görüntülenir ve işlem durdurulur;
- satır 55-62: İşlem başarıyla tamamlandığında, SQL komutlarının yürütülmesi sırasında karşılaşılan hata sayısı görüntülenir;
1. Yürütme
Öncelikle işlem içermeyen bir yürütme gerçekleştirilir. Bunun için, |configuration d’un contexte d’exécution| paragrafında yapıldığı gibi bir yürütme yapılandırması oluşturulur:

- [1-4]'te bir Python yürütme yapılandırması oluşturulur;

- [5]: yürütme yapılandırmasının adı;
- [6]: çalıştırılacak komut dosyasının yolu;
- [7]: komut dosyasının parametreleri;
- [8]: çalıştırma klasörü;
Dolayısıyla bu yapılandırma, bir işlemle birlikte SQL dosyasının çalıştırılmasına karşılık gelir. Yapılandırmayı onaylamak için [Apply] düğmesini kullanın.
Aynı şekilde [mysql mysql-04 without_transaction] yürütme yapılandırmasını da oluşturuyoruz:

Bu yapılandırma, SQL dosyasının işlem olmadan çalıştırılmasına karşılık gelir. Yapılandırmayı onaylamak için [Apply] düğmesini kullanın.
Öncelikle işlem içermeyen sürümü çalıştırıyoruz:

Sonuçlar şu şekildedir:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/databases/mysql/mysql_04.py false
--------------------------------------------------------------------
Exécution du fichier SQL C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\databases\mysql/data/commandes.sql sans transaction
--------------------------------------------------------------------
[drop table personnes] : Exécution réussie
nombre de lignes modifiées : 0
[create table personnes (id int primary key, prenom varchar(30) not null, nom varchar(30) not null, age integer not null, unique (nom,prenom))] : Exécution réussie
nombre de lignes modifiées : 0
[insert into personnes(id, prenom, nom, age) values(1, 'Paul','Langevin',48)] : Exécution réussie
nombre de lignes modifiées : 1
[insert into personnes(id, prenom, nom, age) values (2, 'Sylvie','Lefur',70)] : Exécution réussie
nombre de lignes modifiées : 1
[select prenom, nom, age from personnes] : Exécution réussie
prenom, nom, age,
*****************
('Paul', 'Langevin', 48)
('Sylvie', 'Lefur', 70)
*****************
xx : Erreur (1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xx' at line 1)
[insert into personnes(id, prenom, nom, age) values (3, 'Pierre','Nicazou',35)] : Exécution réussie
nombre de lignes modifiées : 1
[insert into personnes(id, prenom, nom, age) values (4, 'Geraldine','Colou',26)] : Exécution réussie
nombre de lignes modifiées : 1
[insert into personnes(id, prenom, nom, age) values (5, 'Paulette','Girond',56)] : Exécution réussie
nombre de lignes modifiées : 1
[select prenom, nom, age from personnes] : Exécution réussie
prenom, nom, age,
*****************
('Paul', 'Langevin', 48)
('Sylvie', 'Lefur', 70)
('Pierre', 'Nicazou', 35)
('Geraldine', 'Colou', 26)
('Paulette', 'Girond', 56)
*****************
[select nom,prenom from personnes order by nom asc, prenom desc] : Exécution réussie
nom, prenom,
************
('Colou', 'Geraldine')
('Girond', 'Paulette')
('Langevin', 'Paul')
('Lefur', 'Sylvie')
('Nicazou', 'Pierre')
************
[select nom,prenom,age from personnes where age between 20 and 40 order by age desc, nom asc, prenom asc] : Exécution réussie
nom, prenom, age,
*****************
('Nicazou', 'Pierre', 35)
('Colou', 'Geraldine', 26)
*****************
[insert into personnes(id, prenom, nom, age) values(6, 'Josette','Bruneau',46)] : Exécution réussie
nombre de lignes modifiées : 1
[update personnes set age=47 where nom='Bruneau'] : Exécution réussie
nombre de lignes modifiées : 1
[select nom,prenom,age from personnes where nom='Bruneau'] : Exécution réussie
nom, prenom, age,
*****************
('Bruneau', 'Josette', 47)
*****************
[delete from personnes where nom='Bruneau'] : Exécution réussie
nombre de lignes modifiées : 1
[select nom,prenom,age from personnes where nom='Bruneau'] : Exécution réussie
nom, prenom, age,
*****************
*****************
--------------------------------------------------------------------
Exécution terminée
--------------------------------------------------------------------
Il y a eu 1 erreur(s)
xx : Erreur (1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xx' at line 1)
Process finished with exit code 0
Notlar:
-
- satır: Hatanın ardından SQL komutlarının yürütülmesine devam edildiği görülüyor; bunun nedeni, yürütmenin işlem olmadan ve [arrêt=False] parametresiyle gerçekleştirilmiş olmasıdır. Dolayısıyla tüm SQL komutları yürütülmüştür. Bu yürütmeyi yansıtan bir [personnes] tablosu olması gerekir;
phpMyAdmin ile doğrulama:

2. Yürütme
Şimdi [mysql mysql-04 with_transaction] yapılandırmasını çalıştırıyoruz. Sonuçlar şu şekildedir:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/databases/mysql/mysql_04.py true
--------------------------------------------------------------------
Exécution du fichier SQL C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\databases\mysql/data/commandes.sql avec transaction
--------------------------------------------------------------------
[drop table personnes] : Exécution réussie
nombre de lignes modifiées : 0
[create table personnes (id int primary key, prenom varchar(30) not null, nom varchar(30) not null, age integer not null, unique (nom,prenom))] : Exécution réussie
nombre de lignes modifiées : 0
[insert into personnes(id, prenom, nom, age) values(1, 'Paul','Langevin',48)] : Exécution réussie
nombre de lignes modifiées : 1
[insert into personnes(id, prenom, nom, age) values (2, 'Sylvie','Lefur',70)] : Exécution réussie
nombre de lignes modifiées : 1
[select prenom, nom, age from personnes] : Exécution réussie
prenom, nom, age,
*****************
('Paul', 'Langevin', 48)
('Sylvie', 'Lefur', 70)
*****************
xx : Erreur (1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xx' at line 1)
--------------------------------------------------------------------
Exécution terminée
--------------------------------------------------------------------
Il y a eu 1 erreur(s)
xx : Erreur (1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xx' at line 1)
Process finished with exit code 0
Notlar:
-
- satır: Hatanın ardından SQL komutlarının yürütülmediğini görüyoruz; bunun nedeni, yürütmenin bir işlem içinde gerçekleştirilmiş olması ve karşılaşılan ilk hatada işlemi geri alıp SQL komutlarının yürütülmesini durdurmuş olmamızdır. Bu, 9., 11. ve 13. satırlardaki komutların sonuçlarının geri alınmış olduğu anlamına gelir. Dolayısıyla [personnes] tablosunun boş olması gerekir;
phpMyAdmin ile yapılan kontroller:

- [5]'te, [personnes] ve [2] tablolarının boş olduğu görülüyor;
16.7. [mysql_05] komut dosyası: parametreli sorguların kullanımı
[mysql_05] komut dosyası, parametreli sorgu kavramını getirir:
# içe aktarmalar
from mysql.connector import connect, DatabaseError, InterfaceError
# kullanıcı kimliği
ID = "admpersonnes"
PWD = "nobody"
# veritabanı yönetim sisteminin ana bilgisayarı
HOST = "localhost"
# veritabanı kimliği
BASE = "dbpersonnes"
# kişi listesi (soyadı, adı, yaş)
personnes = []
for i in range(5):
personnes.append((i, f"n0{i}", f"p0{i}", i + 10))
personnes.append((40, "d'Aboot", "Y'éna", 18))
# diğer kişi listesi
autresPersonnes = []
for i in range(5):
autresPersonnes.append((i + 100, f"n1{i}", f"p1{i}", i + 20))
autresPersonnes.append((200, "d'Aboot", "F'ilhem", 34))
# SGBD'e erişim
connexion = None
try:
# oturum açma
connexion = connect(host=HOST, user=ID, password=PWD, database=BASE)
# imleç
curseur = connexion.cursor()
# mevcut kayıtların silinmesi
curseur.execute("delete from personnes")
# hazırlanmış sorgu ile kişi bazında ekleme
for personne in personnes:
curseur.execute("insert into personnes(id,nom,prenom,age) values(%s,%s,%s,%s)", personne)
# kişi listesinin toplu olarak eklenmesi
curseur.executemany("insert into personnes(id,nom,prenom,age) values(%s, %s,%s,%s)", autresPersonnes)
# işlemin onaylanması
connexion.commit()
except (DatabaseError, InterfaceError) as erreur:
# hata görüntüleme
print(f"L'erreur suivante s'est produite : {erreur}")
# işlemin iptal edilmesi
if connexion:
connexion.rollback()
finally:
# bağlantıyı kapatma
if connexion:
connexion.close()
Notlar
- 12-21. satırlar: [dbpersonnes] veritabanına eklenecek iki kişi listesi oluşturulur;
-
- satır: veritabanına bağlanılır;
-
- satır: [personnes] tablosunun içeriğinin silinmesi;
- 33-34. satırlar: parametreli bir sorgu ile kişilerin eklenmesi. 34. satırda, ilk parametre çalıştırılacak SQL komutudur. Bu komut eksiktir. İçinde, ikinci parametrenin listesindeki değerlerle tek tek ve sırayla değiştirilecek olan [%s] parametreleri bulunmaktadır;
-
- satır: bu sefer tek bir [curseur.executemany] komutuyla kişilerin eklenmesi. [executemany]'in ikinci parametresi ise bir liste listesidir;
Parametreli sorguların avantajı iki noktada yatmaktadır:
- her çalıştırmada analiz edilmesi gereken 'sabit' sorgulara göre daha hızlı yürütülürler. [executemany] parametreli sorgusu yalnızca bir kez analiz edilir. Ardından, yeniden analiz edilmeden n kez yürütülür;
- parametreli sorguya girilen parametreler doğrulanır. Eğer bunlar, örneğin kesme işareti gibi ayrılmış karakterler içeriyorsa, bu karakterler SQL komutunun yürütülmesini engellememeleri için 'korunur'. Bu noktayı doğrulamak için listeye (16. ve 21. satırlar) apostrof içeren soyad ve adlar eklenmiştir;
phpMyAdmin komutunda elde edilen sonuçlar şunlardır:

- SQL'te ayrık çizgi (apostrof) içeren dizelerin doğru bir şekilde eklendiği görülmektedir. Parametreli sorgu, bu dizeleri 'korumuştur'. Parametreli sorgu olmasaydı, bu işi kendimiz yapmak zorunda kalacaktık;