Λύσεις της επαναληπτικής Δραστηριότητας (ανάλυση προγράμματος sqlite3), των 6 Ερωτήσεων (ΒΔ trade.db, πίνακας customers) και των 6 Εργαστηριακών ασκήσεων (school.db, πίνακας students) του κεφαλαίου 10.
Ερώτηση: Μελετήστε και εκτελέστε το παρακάτω πρόγραμμα, όπου δημιουργείται η Βάση Δεδομένων example2.db και ο πίνακας users, ο οποίος περιέχει το όνομα, το τηλέφωνο, το mail και το συνθηματικό των χρηστών ενός συστήματος. (import sqlite3 / conn = sqlite3.connect('example2.db') / cursor = conn.cursor() / cursor.execute(CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT, phone TEXT, email TEXT unique, password TEXT)) / conn.commit() / conn.close() / db = sqlite3.connect('example2.db') / cursor = db.cursor() / … / cursor.execute(INSERT INTO users(name, phone, email, password) VALUES(?,?,?,?), (name1, phone1, email1, password1)) / print 'First user inserted' / … / db.commit())
Απάντηση:
import sqlite3 — εισαγωγή της βιβλιοθήκης. ② conn = sqlite3.connect('example2.db') — σύνδεση με τη ΒΔ· επειδή το αρχείο δεν υπάρχει, δημιουργείται νέα (κενή) ΒΔ στον τρέχοντα φάκελο. ③ cursor = conn.cursor() — αντικείμενο cursor για την εκτέλεση εντολών SQL. ④ CREATE TABLE IF NOT EXISTS users(...) — δημιουργεί τον πίνακα users με πέντε πεδία: id INTEGER PRIMARY KEY (πρωτεύον κλειδί, συμπληρώνεται αυτόματα με αύξοντα αριθμό), name, phone, email TEXT unique, password TEXT. Το IF NOT EXISTS αποτρέπει σφάλμα αν ο πίνακας υπάρχει ήδη (π.χ. σε δεύτερη εκτέλεση). ⑤ conn.commit() — καταχώρηση της δομής στο αρχείο· ⑥ conn.close() — κλείσιμο της πρώτης σύνδεσης.db = sqlite3.connect('example2.db') και cursor = db.cursor() — νέα σύνδεση με την ίδια ΒΔ (τώρα το αρχείο υπάρχει) και νέος cursor. ⑧ Ορίζονται οι μεταβλητές name1, phone1, email1, password1 (Panagiotis, 2105666858, [email protected], 12345) και name2… (Ioannis, 2105657241, [email protected], abcdef). ⑨ cursor.execute('INSERT INTO users(name, phone, email, password) VALUES(?,?,?,?)', (name1, phone1, email1, password1)) — εισαγωγή εγγραφής με την τεχνική υποκατάστασης με ερωτηματικά: τα τέσσερα ? αντικαθίστανται διαδοχικά από τις τιμές της πλειάδας που δίνεται ως δεύτερο όρισμα της execute· το id δεν δίνεται — το συμπληρώνει η ΒΔ (1). Τυπώνεται «First user inserted». ⑩ Ομοίως η δεύτερη εισαγωγή (id 2) και «Second user inserted». ⑪ db.commit() — οριστική καταχώρηση των δύο εγγραφών στο αρχείο (μέχρι τότε ήταν στη μνήμη).(1, 'Panagiotis', '2105666858', '[email protected]', '12345') και (2, 'Ioannis', '2105657241', '[email protected]', 'abcdef') — ελέγχεται με cursor.execute('SELECT * FROM users'); print cursor.fetchall(). Στην οθόνη εμφανίζονται μόνο τα δύο μηνύματα print.sqlite3.IntegrityError: UNIQUE constraint failed: users.email — ο πίνακας όμως δεν ξαναδημιουργείται χάρη στο IF NOT EXISTS. Επίσης: το πρόγραμμα δεν κλείνει τη δεύτερη σύνδεση — καλό είναι να προστεθούν cursor.close() και db.close(). Η υποκατάσταση με ? είναι ασφαλέστερη από τη συνένωση συμβολοσειρών (αποφυγή SQL injection) και χειρίζεται σωστά τα εισαγωγικά μέσα στις τιμές.Σύνοψη: Δημιουργία/σύνδεση με example2.db, cursor, CREATE TABLE IF NOT EXISTS users (id PRIMARY KEY αυτόματο, email unique), commit/close· νέα σύνδεση, δύο INSERT με υποκατάσταση ? από πλειάδες (id αυτόματα 1, 2), μηνύματα print, commit· επανεκτέλεση → σφάλμα UNIQUE στο email.
Κριτήρια αξιολόγησης:
Ερώτηση: Πώς εισάγονται εντολές της sqlite3 μέσα σε κώδικα Python;
Απάντηση:
import sqlite3 (σελ. 177). ② Δημιουργούμε σύνδεση με τη ΒΔ: conn = sqlite3.connect('όνομα.db') και ένα αντικείμενο cursor: curs = conn.cursor(). ③ Κάθε εντολή SQL γράφεται ως συμβολοσειρά (σε απλά ή τριπλά εισαγωγικά αν πιάνει πολλές γραμμές) και εκτελείται με τη μέθοδο curs.execute('εντολή SQL') — π.χ. curs.execute('SELECT * FROM cars')· για πολλές εγγραφές μαζί curs.executemany('INSERT … VALUES (?,?,…)', λίστα), όπου τα ερωτηματικά υποκαθίστανται από τις τιμές. Πεζά/κεφαλαία στις εντολές SQL είναι αδιάφορα (γράφονται κεφαλαία για διάκριση).conn.commit()· τα αποτελέσματα μιας SELECT διαβάζονται με curs.fetchall() / fetchone() ή με for row in curs.execute(...). ⑤ Στο τέλος curs.close() και conn.close().Σύνοψη: (ενδεικτική) import sqlite3 → conn = sqlite3.connect(...) → curs = conn.cursor() → η εντολή SQL ως συμβολοσειρά μέσα στην curs.execute('…') (ή executemany με ?) → conn.commit() για αλλαγές, fetchall() για SELECT → close().
Κριτήρια αξιολόγησης:
Ερώτηση: Με ποια εντολή μπορούμε να δημιουργήσουμε μια κενή βάση δεδομένων με όνομα trade.db;
Απάντηση:
conn = sqlite3.connect('trade.db') (αφού προηγηθεί import sqlite3). Η connect δημιουργεί αντικείμενο χειριστή σύνδεσης με το αρχείο trade.db· αν το αρχείο δεν υπάρχει, δημιουργείται νέα, κενή βάση δεδομένων με αυτό το όνομα στον φάκελο της Python (σελ. 177). Για άλλον φάκελο δίνουμε τη διαδρομή, π.χ. sqlite3.connect('c:/SQL/trade.db').import sqlite3
conn = sqlite3.connect('trade.db') # δημιουργεί την κενή ΒΔ trade.db (αν δεν υπάρχει)
curs = conn.cursor() # cursor για τις επόμενες εντολές
Σύνοψη: import sqlite3· conn = sqlite3.connect('trade.db') — αν δεν υπάρχει το αρχείο, δημιουργείται νέα κενή ΒΔ.
Κριτήρια αξιολόγησης:
Ερώτηση: Με ποιες εντολές κώδικα μπορούμε να δημιουργήσουμε έναν πίνακα customers με στοιχεία το AFM, Name, City και Phone στη ΒΔ trade.db;
Απάντηση:
import sqlite3
conn = sqlite3.connect('trade.db')
curs = conn.cursor()
curs.execute('''CREATE TABLE customers
(AFM TEXT PRIMARY KEY not null,
Name TEXT,
City TEXT,
Phone TEXT)''')
conn.commit()
CREATE TABLE IF NOT EXISTS customers (...) ώστε να μην προκύπτει σφάλμα σε επανεκτέλεση, ή με επιπλέον πεδίο id INTEGER PRIMARY KEY ως αύξοντα αριθμό και το AFM απλώς unique. Επαληθεύτηκε με εκτέλεση.Σύνοψη: conn = sqlite3.connect('trade.db')· curs = conn.cursor()· curs.execute(CREATE TABLE customers (AFM TEXT PRIMARY KEY, Name TEXT, City TEXT, Phone TEXT))· conn.commit().
Κριτήρια αξιολόγησης:
Ερώτηση: Με ποια εντολή μπορούμε να εισάγουμε στον πίνακα customers τον πελάτη με στοιχεία 012231212, Dimou Manolis, Athens, 212456789120;
Απάντηση:
curs.execute("INSERT INTO customers VALUES ('012231212', 'Dimou Manolis', 'Athens', '212456789120')")
conn.commit()
curs.execute('INSERT INTO customers (AFM, Name, City, Phone) VALUES (?,?,?,?)', ('012231212', 'Dimou Manolis', 'Athens', '212456789120')). Χωρίς το commit η εγγραφή μένει μόνο στη μνήμη.Σύνοψη: curs.execute(INSERT INTO customers VALUES ('012231212', 'Dimou Manolis', 'Athens', '212456789120'))· conn.commit().
Κριτήρια αξιολόγησης:
Ερώτηση: Να εισαχθεί επιπλέον ο πελάτης 0123456789, Gatos Nikos, Athens, 212923876543. Επίσης να τροποποιηθεί η πόλη (city) του πελάτη Gatos σε Larisa.
Απάντηση:
curs.execute("INSERT INTO customers VALUES ('0123456789', 'Gatos Nikos', 'Athens', '212923876543')")
curs.execute("UPDATE customers SET City = 'Larisa' WHERE AFM = '0123456789'")
conn.commit()
WHERE Name = 'Gatos Nikos' (ή WHERE Name LIKE 'Gatos%'). Μετά τις εντολές ο πίνακας περιέχει: ('012231212', 'Dimou Manolis', 'Athens', …) και ('0123456789', 'Gatos Nikos', 'Larisa', …) — επαληθεύτηκε με SELECT * FROM customers. Χωρίς WHERE η UPDATE θα άλλαζε την πόλη όλων των πελατών.Σύνοψη: INSERT INTO customers VALUES ('0123456789', 'Gatos Nikos', 'Athens', '212923876543')· UPDATE customers SET City = 'Larisa' WHERE AFM = '0123456789' (ή Name = 'Gatos Nikos')· commit.
Κριτήρια αξιολόγησης:
Ερώτηση: Να διαγραφούν όλοι οι πελάτες που ως πόλη (city) έχουν την τιμή Athens.
Απάντηση:
curs.execute("DELETE FROM customers WHERE City = 'Athens'")
conn.commit()
DELETE FROM customers θα διέγραφε όλες τις εγγραφές (ο πίνακας θα έμενε κενός αλλά θα υπήρχε — αντίθετα η DROP TABLE customers διαγράφει τον ίδιο τον πίνακα). Καλό είναι πριν τη διαγραφή να ελέγχουμε τι θα διαγραφεί με SELECT * FROM customers WHERE City = 'Athens'.Σύνοψη: DELETE FROM customers WHERE City = 'Athens'· conn.commit() — μένει μόνο ο Gatos (Larisa).
Κριτήρια αξιολόγησης:
Ερώτηση: Δημιουργήστε μια βάση δεδομένων με όνομα school.db.
Απάντηση:
import sqlite3
conn = sqlite3.connect('school.db') # δημιουργεί το αρχείο school.db (κενή ΒΔ) αν δεν υπάρχει
curs = conn.cursor()
connect δημιουργεί το αρχείο school.db στον τρέχοντα φάκελο (ή στη διαδρομή που δίνουμε) και επιστρέφει το αντικείμενο σύνδεσης· ο cursor θα χρησιμοποιηθεί σε όλες τις επόμενες ασκήσεις. Η ΒΔ είναι κενή μέχρι να δημιουργήσουμε πίνακες.Σύνοψη: import sqlite3· conn = sqlite3.connect('school.db')· curs = conn.cursor().
Κριτήρια αξιολόγησης:
Ερώτηση: Εισάγετε ένα πίνακα με όνομα students, ο οποίος θα περιέχει στοιχεία των μαθητών της τάξης σας, επιλέγοντας εσείς τιμές για το πλήθος και τον τύπο των στοιχείων.
Απάντηση:
curs.execute('''CREATE TABLE IF NOT EXISTS students
(id INTEGER PRIMARY KEY,
surname TEXT,
name TEXT,
address TEXT,
phone TEXT,
grade REAL)''')
conn.commit()
Σύνοψη: CREATE TABLE students (id INTEGER PRIMARY KEY, surname TEXT, name TEXT, address TEXT, phone TEXT, grade REAL)· commit.
Κριτήρια αξιολόγησης:
Ερώτηση: Εισάγετε τα στοιχεία ενός μαθητή και στη συνέχεια εισάγετε, όλα μαζί, τα στοιχεία 9 άλλων μαθητών.
Απάντηση:
# ένας μαθητής
curs.execute("INSERT INTO students VALUES (1, 'Papadopoulou', 'Maria', 'Ermou 5', '6971111111', 17.5)")
# εννέα μαθητές μαζί
mathites = [(2, 'Nikolaou', 'Giorgos', 'Athinas 10', '6972222222', 15.2),
(3, 'Dimou', 'Eleni', 'Patision 3', '6973333333', 18.9),
(4, 'Alexiou', 'Kostas', 'Stadiou 7', '6974444444', 12.4),
(5, 'Vasileiou', 'Anna', 'Solonos 1', '6975555555', 19.6),
(6, 'Georgiou', 'Petros', 'Omirou 2', '6976666666', 14.0),
(7, 'Ioannou', 'Sofia', 'Akadimias 9', '6977777777', 16.3),
(8, 'Karali', 'Dimitra', 'Kolokotroni 4', '6978888888', 13.7),
(9, 'Lambrou', 'Nikos', 'Panepistimiou 8', '6979999999', 17.1),
(10, 'Markou', 'Christina', 'Mitropoleos 6', '6970000000', 18.2)]
curs.executemany('INSERT INTO students VALUES (?,?,?,?,?,?)', mathites)
conn.commit()
INSERT INTO students (surname, name, …) VALUES (?,?,?,?,?)), η ΒΔ το συμπληρώνει αυτόματα. Το commit καταχωρεί και τις 10 εγγραφές.Σύνοψη: Μία INSERT … VALUES (…) για τον πρώτο· λίστα 9 πλειάδων + curs.executemany('INSERT INTO students VALUES (?,?,?,?,?,?)', λίστα)· commit.
Κριτήρια αξιολόγησης:
Ερώτηση: Τροποποιήστε κάποιο από τα στοιχεία ενός μαθητή, όπως για παράδειγμα τη διεύθυνση ή το τηλέφωνό του.
Απάντηση:
# αλλαγή τηλεφώνου του μαθητή με id 4 (Alexiou Kostas)
curs.execute("UPDATE students SET phone = '6980000000' WHERE id = 4")
# αλλαγή διεύθυνσης με βάση το επώνυμο
curs.execute("UPDATE students SET address = 'Ippokratous 12' WHERE surname = 'Dimou'")
conn.commit()
SET phone = '…', address = '…'. Χωρίς WHERE θα άλλαζαν όλοι οι μαθητές. Επαληθεύτηκε με εκτέλεση.Σύνοψη: UPDATE students SET phone = '6980000000' WHERE id = 4 (ή SET address = … WHERE surname = …)· commit.
Κριτήρια αξιολόγησης:
Ερώτηση: Διαγράψτε ένα μαθητή.
Απάντηση:
curs.execute('DELETE FROM students WHERE id = 6') # διαγραφή του Georgiou Petros
conn.commit()
WHERE surname = 'Georgiou' AND name = 'Petros'. Προσοχή: χωρίς WHERE διαγράφονται όλες οι εγγραφές· η διαγραφή δεν αναιρείται μετά το commit, γι' αυτό ελέγχουμε πρώτα με SELECT ποια εγγραφή θα διαγραφεί.Σύνοψη: DELETE FROM students WHERE id = 6· commit — προσοχή στο WHERE.
Κριτήρια αξιολόγησης:
Ερώτηση: Εμφανίστε όλους τους μαθητές ταξινομημένους ως προς το επίθετό τους. Εμφανίστε ξανά όλους τους μαθητές ταξινομημένους ως προς το όνομά τους.
Απάντηση:
print 'Μαθητές κατά επώνυμο:'
for row in curs.execute('SELECT * FROM students ORDER BY surname ASC'):
print row
print 'Μαθητές κατά όνομα:'
curs.execute('SELECT * FROM students ORDER BY name') # ASC είναι η προεπιλογή
for row in curs.fetchall():
print row
curs.close()
conn.close()
Η ORDER BY surname ταξινομεί αλφαβητικά κατά επώνυμο (Alexiou, Dimou, Ioannou, Karali, …), η ORDER BY name κατά όνομα (Anna, Christina, Dimitra, …) — επαληθεύτηκε με εκτέλεση. Το ASC μπορεί να παραλειφθεί, το DESC (φθίνουσα) πρέπει να δηλωθεί. Για ταξινόμηση με δεύτερο κριτήριο: ORDER BY surname, name. Οι εγγραφές διαβάζονται είτε με for row in curs.execute(...) είτε με fetchall(). Στο τέλος κλείνουμε cursor και σύνδεση.
Σύνοψη: SELECT FROM students ORDER BY surname (ASC) και SELECT FROM students ORDER BY name· εμφάνιση με for row in … / fetchall()· close.
Κριτήρια αξιολόγησης: