Βάσεις Δεδομένων Ι - 05 SQL Μέρος 3 ο (Constraints & Joins) Φώτης Κόκκορας (MSc/PhD) Τμήμα Μηχανικών Πληροφορικής ΤΕ ΤΕΙ Θεσσαλίας
Πρόσθετες Διαφάνειες σε Προηγούμενα Θέματα...σε Διαγραφή Πλειάδων Σημασιολογία της εντολής DELETE Στην SQL, η διαγραφή πλειάδων (εγγραφών) λειτουργεί σε δύο στάδια: 1) Σημειώνονται όλες οι πλειάδες που πληρούν τη συνθήκη (WHERE) διαγραφής (εφόσον υπάρχει) 2) Διαγράφονται όλες οι πλειάδες που σημειώθηκαν στο στάδιο (1). Παράδειγμα: Έστω ο πίνακας Beers με 10 εγγραφές και ότι θέλουμε να σβήσουμε τις εγγραφές του πίνακα Beers αν είναι πάνω από 5. Αυτός ο έλεγχος (είναι οι εγγραφές πάνω από 5;) και η απόφαση του τι θα διαγραφεί γίνεται αρχικά. Δηλαδή στην προκειμένη περίπτωση θα διαγραφούν όλες οι καταχωρήσεις. Είναι λάθος να ειπωθεί ότι "μόλις διαγραφούν οι 5 από τις 10 εγγραφές τότε η συνθήκη παύει να ισχύει, άρα τελικά στον πίνακα Beers θα μείνουν 5 εγγραφές". Η ακριβής συμπεριφορά εξαρτάται από κάθε σύστημα RDBMS και θα πρέπει να το ελέγχετε στη τεκμηρίωση του συστήματος. Για παράδειγμα, στον MySQL Server δεν επιτρέπεται σε μια εντολή DELETE σε κάποιον πίνακα, να υπάρχει συνθήκη στο WHERE της δήλωσης που να εμπλέκει τον ίδιο πίνακα! Η ακόλουθη δήλωση προκαλεί error : DELETE FROM Beers WHERE 3< (SELECT count(name) FROM Beers); Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 2 - Βάσεις Δεδομένων Ι
Πρόσθετες Διαφάνειες σε Προηγούμενα Θέματα...σε εντολές UNION, INTERSECTION και DIFFERENCE Παρόλο που οι εντολές SELECT...FROM...WHERE δύναται να επιστρέψουν πολλαπλά αποτελέσματα (με την έννοια ότι μια πλειάδα μπορεί να εμφανίζεται περισσότερες από μια φορές στα αποτελέσματα), δεν ισχύει το ίδιο για τις UNION, INTERSECTION και DIFFERENCE. Αυτές οι εντολές επιστρέφουν αλγεβρικό σύνολο (set) και στα αλγεβρικά σύνολα δεν μπορεί μια πλειάδα να επαναλαμβάνεται! Όπως έχει ειπωθεί σε παλαιότερα slides, αν σε ένα ερώτημα SELECT δεν επιθυμούμε πιθανές επαναλήψεις πλειάδων, τότε χρησιμοποιούμε τον τελεστή DISTINCT. Από μαθηματικής σκοπιάς (θεωρία συνόλων), τα ερωτήματα SELECT επιστρέφουν bag (και όχι set). Το bag (ή multiset) είναι μια γενίκευση της έννοιας του set στο οποίο ένα στοιχείο του συνόλου επιτρέπεται να υπάρχει περισσότερες από μία φορές. Ο λόγος της διαφορετικής αντιμετώπισης είναι οι επιδόσεις: Στα ερωτήματα SELECT είναι βολικότερο να αποφευχθεί η απαλοιφή πολλαπλών εγγραφών καθώς επιβαρύνει αρκετά την διαδικασία. Αν χρειάζεται όμως, το ζητάμε με DISTINCT. Στα ερωτήματα INTERSECTION και DIFFERENCE, για λόγους απόδοσης, προηγείται ταξινόμηση των πλειάδων, κάτι που καθιστά την απαλοιφή των πολλαπλών εύκολη υπόθεση. Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 3 - Βάσεις Δεδομένων Ι
Περιορισμοί (Constraints) Χρησιμοποιούνται για να...περιορίσουμε το είδος των δεδομένων που μπορεί να μπουν σε μια στήλη ενός πίνακα. Το περιορισμό επιβάλει το Σύστημα Διαχείρισης Βάσεων Δεδομένων (ΣΔΒΨ ή DBMS). Η σημασία τους είναι ζωτική καθώς αν δεν τους χρησιμοποιήσουμε (τους παρέχει έτοιμους το DBMS) θα υποχρεωθούμε αργότερα να υλοποιήσουμε πολύπλοκους μηχανισμούς ελέγχων στο επίπεδο της εφαρμογής που χρησιμοποιεί την database. ΔΕΝ είναι καθόλου έξυπνο να ξαναφτιάξουμε κάτι που το παρέχει έτοιμο το DBMS!!! Ορίζονται είτε στη φάση δημιουργίας ενός πίνακα (δηλ. στην εντολή CREATE TABLE) ή εκ των υστέρων, μεταβάλλοντας τον πίνακα (δηλ. με δηλώσεις ALTER TABLE). Οι κυριότεροι περιορισμοί σε επίπεδο στηλών είναι (αναλύονται στη συνέχεια): NOT NULL: το πεδίο πρέπει να έχει οπωσδήποτε τιμή DEFAULT: ορίζει μια τιμή για το πεδίο, σε περίπτωση που δεν δοθεί από το χρήστη. PRIMARY KEY: το πεδίο (ή τα πεδία) αποτελεί πρωτεύον κλειδί του πίνακα UNIQUE: το πεδίο πρέπει να έχει τιμή που δεν επαναλαμβάνεται στο ίδιο πεδίο άλλης εγγραφής (πλειάδας) FOREIGN KEY: το πεδίο αποτελεί πρωτεύον κλειδί σε κάποιον άλλο (συσχετιζόμενο) πίνακα Ενδιαφέρον εδώ έχουν οι μηχανισμοί τήρησης των περιορισμών του "ξένου κλειδιού". CHECK: περιορίζει τις τιμές που είναι αποδεκτές σε ένα πεδίο Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 4 - Βάσεις Δεδομένων Ι
NOT NULL Η στήλη πρέπει οπωσδήποτε να πάρει τιμή. Άρα δεν μπορεί να γίνει INSERT ή UPDATE μιας εγγραφής χωρίς να δοθεί τιμή σε στήλη που έχει περιορισμό NOT NULL....εκτός κι αν το πεδίο έχει επιπλέον ορισμένη και DEFAULT τιμή! (βλ. επόμενο slide) Παράδειγμα δήλωσης του περιορισμού CREATE TABLE Beers ( name VARCHAR(45) NOT NULL, manf VARCHAR(45) NOT NULL ) Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 5 - Βάσεις Δεδομένων Ι
DEFAULT Δεν πρόκειται για περιορισμό, με την αυστηρή έννοια του όρου. Είναι μια τιμή που θα μπει στην στήλη αν δεν δοθεί άλλη τιμή. Παράδειγμα δήλωσης του περιορισμού CREATE TABLE Drinker ( name VARCHAR(45) NOT NULL, city VARCHAR(45) NOT NULL DEFAULT 'Larisa' ) Αν δεν δίνεται τιμή στο city, θα μπαίνει αυτόματα 'Larisa'. Σε μερικά DBMS μπορεί να οριστούν ως DEFAULT τιμές, συναρτήσεις συστήματος που παράγουν κάποια τιμή (πχ την τρέχουσα ημερομηνία). Προσοχή στις ιδιαιτερότητες κάθε DBMS καθώς υπάρχουν διαφορές στον τρόπο που γίνονται κάποια πράγματα: http://www.w3schools.com/sql/sql_default.asp Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 6 - Βάσεις Δεδομένων Ι
PRIMARY KEY Ο ρόλος του πρωτεύοντος κλειδιού είναι να προσδιορίζει μοναδικά κάθε εγγραφή σε ένα πίνακα. Για αυτόν το λόγο, κάθε πλειάδα έχει διαφορετική τιμή στη στήλη (ή τις στήλες) του πρωτεύοντος κλειδιού από κάθε άλλη πλειάδα. Το πρωτεύον κλειδί ΔΕΝ μπορεί να πάρει τιμή NULL. Κάθε πίνακας πρέπει να έχει ένα πρωτεύον κλειδί. Παράδειγμα δήλωσης του περιορισμού Για απλό πρωτεύον κλειδί μιας στήλης: CREATE TABLE Beers ( name CHAR(20) PRIMARY KEY, manf CHAR(20) ) Για σύνθετο πρωτεύον κλειδί: CREATE TABLE Sells ( bar CHAR(20), beer VARCHAR(20), price REAL, PRIMARY KEY (bar, beer) ); Περισσότερα στο URL: http://www.w3schools.com/sql/sql_primarykey.asp Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 7 - Βάσεις Δεδομένων Ι
UNIQUE Ο περιορισμός UNIQUE μοιάζει με αυτόν του πρωτεύοντος κλειδιού καθώς δεν επιτρέπει σε δύο πλειάδες μιας σχέσης να έχουν ίδια τιμή σε αυτό το γνώρισμα, πλην όμως, σε αντίθεση με το πρωτεύον κλειδί: η στήλη με τη ρύθμιση UNIQUE μπορεί να πάρει τιμή NULL σε πολλές πλειάδες μπορούμε να έχουμε πολλές στήλες με τη ρύθμιση UNIQUE (αλλά μόνο ένα πρωτεύον κλειδί) το UNIQUE μπαίνει μόνο σε μία στήλη ενώ το πρωτεύον κλειδί μπορεί να οριστεί με πολλές Άρα: κάθε PRIMARY KEY έχει μέσα του και ένα περιορισμό τύπου UNIQUE το UNIQUE δεν υποκαθιστά πλήρως το PRIMARY KEY Παράδειγμα δήλωσης του περιορισμού Σε MySQL είναι αναγνωρίσιμη σύνταξη όμοια με αυτή του PRIMARY KEY. Στο MySQL Workbench, στη σχεδίαση database, το checkbox UQ παράγει τη δήλωση: CREATE TABLE table1 ( id INT(11) NOT NULL, field1 VARCHAR(45) NULL, PRIMARY KEY (id), UNIQUE INDEX table1col (field1 ASC) ) δηλαδή φτιάχνει ένα ευρετήριο το οποίο δεν επιτρέπει πολλαπλές καταχωρήσεις. Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 8 - Βάσεις Δεδομένων Ι
FOREIGN KEY (FK) (1/6) Πρόκειται για τον πιο σημαντικό περιορισμό σε βάσεις δεδομένων καθώς επιτρέπει να υλοποιήσουμε με βάση αυτόν, μηχανισμούς ακεραιότητας δεδομένων, δηλ. μηχανισμούς που θα εξασφαλίσουν ότι τα δεδομένα της database είναι "σωστά". Θα δούμε τι σημαίνει το "σωστά" στη συνέχεια. Σε μια σχέση (πίνακα) τα foreign keys (ξένα κλειδιά) είναι γνωρίσματα (στήλες) τα οποία αποτελούν πρωτεύων κλειδί σε κάποιο άλλο πίνακα της ίδιας database. Για παράδειγμα, στην mybeersdb στον πίνακα Sells(bar, beer, price): το γνώρισμα bar είναι πρωτεύον κλειδί στον πίνακα Bars το γνώρισμα beer είναι πρωτεύον κλειδί στον πίνακα Beers Προφανώς δεν υπάρχει ανάγκη το όνομα των πεδίων που είναι foreign keys να είναι ίδιο με αυτό των σχετικών primary keys πεδίων. Είναι όμως μια πολύ καλή τακτική να δίνετε τα ίδια ονόματα για δική σας ευκολία αλλά και γιατί πολλά ΣΔΒΔ το αναγνωρίζουν αυτόματα και σας βοηθούν στη σχεδίαση. Είναι επίσης προφανές ότι ο τύπος των πεδίων (foreign key και συσχετιζόμενο primary key) πρέπει να είναι ίδιος. Μόνο τυχόν ρύθμιση AI (auto incremental) σε τεχνητό primary key ΔΕΝ πρέπει να επαναλαμβάνεται στη δήλωση του foreign key. Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 9 - Βάσεις Δεδομένων Ι
FOREIGN KEY (2/6) Τα foreign keys δηλώνονται μέσω της δήλωσης REFERENCES που μπαίνει: είτε μετά το όνομα του γνωρίσματος (εφόσον το foreign key αποτελείται από ένα γνώρισμα) ή ως ξεχωριστή δήλωση στο schema του πίνακα με την ακόλουθη σύνταξη FOREIGN KEY (<λίστα γνωρισμάτων>) REFERENCES <relation> (<λίστα γνωρισμάτων>) Παράδειγμα CREATE TABLE Beers ( /* ο πίνακας που ορίζει το πεδίο που θα χρησιμοποιηθεί ως foreign key */ name CHAR(20) PRIMARY KEY, manf CHAR(20) ); /* πρώτος τρόπος δήλωσης */ CREATE TABLE Sells ( /* ο πίνακας που επαναχρησιμοποιεί το πεδίο name του Beers ως foreign key */ bar CHAR(20), beer CHAR(20) REFERENCES Beers (name), price REAL ); /* δεύτερος τρόπος δήλωσης */ CREATE TABLE Sells ( /* ο πίνακας που επαναχρησιμοποιεί το πεδίο name του Beers ως foreign key */ bar CHAR(20), beer CHAR(20), price REAL, FOREIGN KEY (beer) REFERENCES Beers (name) ); Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 10 - Βάσεις Δεδομένων Ι
FOREIGN KEY (3/6) Επιβολή Περιορισμών Ξένου Κλειδιού Κανόνες Ακεραιότητας Όταν υπάρχει περιορισμός ξένου κλειδιού από τη σχέση R (που φιλοξενεί το ξένο κλειδί) στη σχέση S (που ορίζει το πεδίο που χρησιμοποιείται ως ξένο κλειδί), δύο είναι οι πιθανοί κίνδυνοι για παραβίαση του περιορισμού: Εντολή INSERT ή UPDATE στη σχέση R (που φιλοξενεί το ξένο κλειδί) δίνει στο πεδίο ξένου κλειδιού τιμή που δεν υπάρχει στη σχέση S (που ορίζει το πεδίο του ξένου κλειδιού). π.χ. στη σχέση Sells(bar,beer,price) δεν μπορούμε να καταχωρήσουμε εγγραφή με τιμή στο bar που δεν υπάρχει στη σχέση Bars, ή/και με τιμή στο beer που δεν υπάρχει στη σχέση Beers. Διαγραφή ή μεταβολή (DELETE ή UPDATE) κάποιας πλειάδας (εγγραφής) στη σχέση S, δημιουργεί στην R εγγραφές που έχουν τιμές στο ξένο κλειδί που δεν υπάρχουν! π.χ. στη σχέση Beers, δεν μπορούμε ανεξέλεγκτα να διαγράψουμε μια πλειάδα που αφορά σε μπύρα της οποίας το name χρησιμοποιείται στο πεδίο beer της σχέσης Sells. Στην πρώτη περίπτωση τα πράγματα είναι ξεκάθαρα: τέτοιου είδους εντολή πρέπει να απορριφθεί και αυτό γίνεται αυτόματα από το ΣΔΒΔ, εφόσον δηλωθεί κάτι τέτοιο. Δεν υπάρχει απάντηση στο τι είναι σωστό να κάνουμε για τη δεύτερη περίπτωση. Το σίγουρο όμως είναι ότι ΠΡΕΠΕΙ να κάνουμε κάτι. Είναι καθαρά θέμα του τι θέλουμε εμείς να γίνεται και προφανώς αυτό το καθορίζει η εφαρμογή μας. Οι 3+1 επιλογές που έχουμε αναλύονται στη συνέχεια... Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 11 - Βάσεις Δεδομένων Ι
FOREIGN KEY (4/6) Έστω το παράδειγμα όπου R=Sells(bar,beer,price) και S=Beers(name,κτλ). Σε πιθανή εντολή DELETE ή UPDATE στον πίνακα Beers, ο περιορισμός ακεραι ότητας ξένου κλειδιού μας επιβάλει να κάνουμε ένα από τα ακόλουθα: RESTRICT: απαγόρευση η μεταβολή απορρίπτεται από το ΣΔΒΔ CASCADE: οι αλλαγές προωθούνται και στην σχέση Sells Αν έγινε διαγραφή (DELETE) μπύρας, τότε διαγράφονται από τον Sells οι σχετιζόμενες εγγραφές. Αν έγινε μεταβολή (UPDATE) στο name του Beers, αλλάζει όμοια το πεδίο beer του Sells. SET NULL: Στο πεδίο beer των σχετικών εγγραφών του Sells μπαίνει η τιμή NULL. Κάποιο από τα παραπάνω θα γίνεται αυτόματα από το ΣΔΒΔ, αρκεί να έχει δηλωθεί "τι", στη σχεδίαση της database. H 4 η επιλογή που έχουμε (είπαμε υπάρχουν 3+1 επιλογές) είναι να μην κάνουμε τίποτε (NO ACTION) και να το επιτρέψουμε να γίνει. Αυτό ως επιλογή στέκει μόνο αν σε επίπεδο εφαρμογής, υλοποιήσουμε εμείς μια από τις παραπάνω 3 πολιτικές. Αντιλαμβάνεστε ότι αν δεν κάνουμε τίποτε (no action), θα καταλήξουμε με μια άχρηστη database, άρα η 4 η επιλογή υφίσταται μόνο θεωρητικά, εκτός κι αν υλοποιήσετε μόνοι σας στο επίπεδο της εφαρμογής που θα χρησιμοποιεί την database, τις 3 σωστές πολιτικές που αναφέρθηκαν! Κάτι τέτοιο είναι επίπονο και θα σας βάλει τεράστιο φόρτο χωρίς λόγο!!! Σε MySQL, η InnoDB engine (η default) υποστηρίζει τα παραπάνω, η MyISAM όχι! Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 12 - Βάσεις Δεδομένων Ι
Παράδειγμα CASCADE: FOREIGN KEY (5/6) Σε διαγραφή της μπύρας Budweiser από τον Beers αυτόματα θα διαγραφούν και όλες οι πλειάδες του Sells που έχουν beer='budweiser'. Σε μεταβολή της μπύρας Budweiser έστω αλλάζουμε το όνομά της σε 'Bud' αυτόματα θα γίνει η ίδια αλλαγή σε όλες τις πλειάδες του Sells που έχουν beer='budweiser'. Παράδειγμα SET NULL: Σε διαγραφή της μπύρας Budweiser από τον Beers αυτόματα θα μπει τιμή NULL στο πεδίο beer, σε όλες τις πλειάδες του Sells που έχουν beer='budweiser'. Σε μεταβολή της μπύρας Budweiser έστω αλλάζουμε το όνομά της σε 'Bud' αυτόματα θα μπει τιμή NULL στο πεδίο beer, σε όλες τις πλειάδες του Sells που έχουν beer=' Budweiser'. Συνήθως, στις περιπτώσεις UPDATE θέλουμε/βάζουμε CASCADE ενώ στις περιπτώσεις DELETE εξαρτάται καθαρά από το τι θέλει η εφαρμογή με συνήθεις επιλογές τα RESTRICT και CASCADE. Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 13 - Βάσεις Δεδομένων Ι
FOREIGN KEY (6/6) Πώς ορίζουμε περιορισμούς ξένου κλειδιού Στη δήλωση ξένου κλειδιού, επιτρέπεται να ορίσουμε τις πολιτικές που θέλουμε να ισχύουν, ξεχωριστά για τις διαγραφές (DELETE) και τις μεταβολές (UPDATE), ως εξής: ON DELETE <ενέργεια> ON UPDATE <ενέργεια> όπου <ενέργεια> σε MySQL server είναι ένα εκ των RESTRICT, CASCADE, NO ACTION, SET NULL Ελέγξτε την ακριβή σύνταξη που ισχύει για το ΣΔΒΔ που χρησιμοποιείτε. Σε όλα τα slide του μαθήματος δίνεται προτεραιότητα στη σύνταξη του MySQL Server. Παράδειγμα από την mybeersbd CREATE TABLE Sells ( bar VARCHAR(45) NOT NULL, beer VARCHAR(45) NOT NULL, price DECIMAL(3,2) NOT NULL, PRIMARY KEY (bar, beer), (συνέχεια δεξιά) CONSTRAINT fk_sells_bars FOREIGN KEY (bar) REFERENCES Bars(name) ON DELETE RESTRICT ON UPDATE CASCADE, CONSTRAINT fk_sells_beers FOREIGN KEY (beer) REFERENCES Beers(name) ON DELETE RESTRICT ON UPDATE CASCADE ) Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 14 - Βάσεις Δεδομένων Ι
Κανόνες Ακεραιότητας FK σε Workbench Στο MySQL Workbench, τα ξένα κλειδιά ορίζονται εύκολα με τη βοήθεια του button που επισημαίνεται στην εικόνα. Π.χ. το fk_sells_bars φτιάχνεται ως εξής: A. πατάμε το κίτρινο button B. κάνουμε κλικ στο πεδίο που αποτελεί ξένο κλειδί, δηλ. στο Sells.bar C. κάνουμε κλικ στο ίδιο πεδίο αλλά στον πίνακα που το ορίζει, δηλ. στο Bars.name Η δήλωση ξένου κλειδιού αποθηκεύεται στο schema της σχέσης που το περιέχει (εδώ στη Sells). Οι κανόνες ακεραιότητας στο παραπάνω ξένο κλειδί ρυθμίζονται από την καρτέλα Foreign Keys των ρυθμίσεων του πίνακα Sells (βλ. εικόνα). Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 15 - Βάσεις Δεδομένων Ι
CHECK (σε γνωρίσματα) Μέσω της δήλωσης CHECK μπορούμε να ορίσουμε περιορισμούς στις τιμές που επιτρέπεται να πάρει μια στήλη. Σύνταξη: CHECK <συνθήκη> Παράδειγμα: CREATE TABLE Sells ( bar CHAR(20), beer CHAR(20) CHECK ( beer IN (SELECT name FROM Beers)), price REAL CHECK ( price <= 5.00 ) ); Το πεδίο beer επιτρέπεται να πάρει τιμές από τις τιμές του πεδίου name του πίνακα Beers. Το πεδίο price επιτρέπεται να πάρει τιμές το πολύ μέχρι 5. Δηλαδή, η <συνθήκη> μπορεί να χρησιμοποιεί το όνομα του πεδίου. Άλλα όμως πεδία ή σχέσεις μπορούν να εμπλακούν στην συνθήκη μόνο σε υποερώτημα! ΠΡΟΣΟΧΗ! Οι παραπάνω έλεγχοι εφαρμόζονται μόνο κατά το INSERT ή το UPDATE Παράδειγμα #1: το CHECK ( price <= 5.00 ) ελέγχει κάθε νέα τιμή και απορρίπτει την καταχώρηση ή μεταβολή της πλειάδας αν το price είναι μεγαλύτερο από 5. Παράδειγμα #2: το CHECK ( beer IN (SELECT name FROM Beers)) ΔΕΝ ελέγχεται όταν μια μπύρα διαγράφεται (DELETE) από τον πίνακα Beers. Δηλαδή, είναι λάθος να υποθέσετε ότι αντικαθιστά τον περιορισμό ξένου κλειδιού! Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 16 - Βάσεις Δεδομένων Ι
CHECK (ως στοιχεία στο schema) Εκτός από γνωρίσματα οι δηλώσεις CHECK <συνθήκη> μπορεί να μπουν και ως στοιχεία στο schema μιας σχέσης. Όπως και πριν, έτσι και εδώ: η <συνθήκη> μπορεί να αναφέρεται απευθείας σε οποιοδήποτε γνώρισμα της σχέσης. Εμπλοκή όμως άλλων σχέσεων (και των γνωρισμάτων τους) απαιτεί τη χρήση υποερωτήματος. η <συνθήκη> ελέγχεται ότι ισχύει μόνο κατά τη φάση του INSERT και του UPDATE Παράδειγμα: CREATE TABLE Sells ( bar CHAR(20), beer CHAR(20), price REAL, CHECK (bar = 'Caravan' OR price <= 5.00) ); Δηλαδή, μόνο στο bar Caravan μπορεί η μπύρα να κοστίζει πάνω από 5! Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 17 - Βάσεις Δεδομένων Ι
JOINs (1/3) Ο τελεστής JOIN χρησιμοποιείται σε μια έκφραση SQL όταν απευθυνόμαστε σε δεδομένα δύο πινάκων και αξιοποιεί κάποια σχέση που υπάρχει μεταξύ συγκεκριμένων γνωρισμάτων των πινάκων. Έχουμε ήδη αναφέρει έναν παρόμοιας φύσης τελεστή, το ',' (κόμμα!!) μέσω του οποίου διαχωρίζουμε τους πίνακες στη σύνταξη του τελεστή FROM. Στην πραγματικότητα δεν τους διαχωρίζουμε αλλά, όπως έχουμε πει, τους συνδυάζουμε (γινόμενο σχέσεων βλ. εικόνα): Υπενθυμίζεται ότι έχουμε έλεγχο στις παραγόμενες πλειάδες βάζοντας τυχόν περιορισμό που μπορεί να υπάρχει μεταξύ πεδίων στο WHERE τμήμα μιας SELECT δήλωσης. Δεν είναι βέβαια αυτό το JOIN! Ο τελεστής JOIN δίνει ακόμη μεγαλύτερο έλεγχο στο πώς θα συνδυαστούν οι πλειάδες των επί μέρους σχέσεων. Έστω λοιπόν οι σχέσεις R και S του σχήματος δεξιά... Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 18 - Βάσεις Δεδομένων Ι
JOIN (ή INNER JOIN) Στην τελική σχέση συμμετέχουν ΜΟΝΟ οι γραμμές των δύο πινάκων που συσχετίζονται. Παράδειγμα: U = R JOIN S ON R.B=S.B JOINs (2/3) FULL JOIN (ή OUTER JOIN, ή FULL OUTER JOIN) Στην τελική σχέση συμμετέχουν όλες οι γραμμές των δύο πινάκων, ακόμη κι αν μια δεν συσχετίζεται με κάποια γραμμή στον άλλο πίνακα. Παράδειγμα: U = R FULL JOIN S ON R.B=S.B αν υπάρχει συσχετισμός (βλ. 1 η γραμμή στο παράδειγμα), στην παραγόμενη πλειάδα συμμετέχουν οι τιμές των δύο πλειάδων αν δεν υπάρχει συσχετισμός, συμμετέχει η μία πλειάδα και τα υπόλοιπα πεδία συμπληρώνονται με NULL (βλ. 2 η και 3 η γραμμή στο παράδειγμα) δηλ. αυτό γίνεται και στους δύο πίνακες Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 19 - Βάσεις Δεδομένων Ι
LEFT JOIN (ή LEFT OUTER JOIN) JOINs (3/3) Στην τελική σχέση συμμετέχουν ΜΟΝΟ οι γραμμές του ΑΡΙΣΤΕΡΟΥ πίνακα, ασχέτως αν συσχετίζονται ή όχι με γραμμές του άλλου πίνακα. Παράδειγμα: U = R LEFT JOIN S ON R.B=S.B RIGHT JOIN (ή RIGHT OUTER JOIN) Στην τελική σχέση συμμετέχουν ΜΟΝΟ οι γραμμές του ΔΕΞΙΟΥ πίνακα, ασχέτως αν συσχετίζονται ή όχι με γραμμές του άλλου πίνακα. Παράδειγμα: U = R RIGHT JOIN S ON R.B=S.B Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 20 - Βάσεις Δεδομένων Ι
Πόσες μπύρες αρέσουν σε κάθε drinker; SELECT drinker, count(beer) FROM likes GROUP BY drinker; Παράδειγμα σε mybeersdb Το παραπάνω ερώτημα δεν μας λέει ρητά για τους υπόλοιπους drinkers, ακόμη κι αν ρωτήσουμε ως εξής: SELECT name, count(beer) FROM drinkers, likes WHERE name=drinker GROUP BY name; Βάζοντας όμως LEFT JOIN: SELECT name, count(beer) FROM drinkers LEFT JOIN likes ON name=drinker GROUP BY name; έχουμε αποτέλεσμα για όλους τους drinkers. Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 21 - Βάσεις Δεδομένων Ι
Στο σημείο αυτό ολοκληρώνεται η παρουσίαση των βασικών στοιχείων της γλώσσας SQL. Δεν την έχουμε καλύψει κατά 100% - κάτι τέτοιο είναι δύσκολο αλλά κυρίως χωρίς ουσία καθώς θα ήταν εξαιρετικά χρονοβόρο και αμφιβόλου αξίας. Καλύψαμε αναλυτικά εκείνα τα στοιχεία που αποτελούν βασικά εφόδια για να ασχοληθεί κανείς σοβαρά με την SQL και το κυριότερο, να μπορεί να ανταποκριθεί αξιοπρεπώς στις απαιτήσεις ενός τυπικού, μέσης πολυπλοκότητας project. Η τριβή με το αντικείμενο και η περαιτέρω μελέτη της εκάστοτε τεκμηρίωσης θα σας δώσει τις διάφορες λεπτομέρειες που σε αυτή τη φάση δεν έχουν σημασία. Να τονιστεί για μια ακόμη φορά ότι υπάρχουν μικροδιαφορές στη ακριβή σύνταξη εντολών μεταξύ των διαφόρων ΣΔΒΔ. Στα παραδείγματα ακολουθήθηκε ο τρόπος του MySQL server. Αν δουλέψετε σε άλλη πλατφόρμα οφείλετε να ρίξετε μια ματιά στην τεκμηρίωσή της (documentation) ώστε να δείτε τυχόν διαφορές. Οι έννοιες ως επί των πλείστων είναι ίδιες η σύνταξη ίσως αλλάζει! Μια γρήγορη εικόνα για το τι ισχύει στις διάφορες υλοποιήσεις ΣΔΒΔ δίνει (ποιο άλλο!) το site w3schools στο τμήμα του για SQL. Κάντε το bookmark, είναι must! http://www.w3schools.com/sql Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 22 - Βάσεις Δεδομένων Ι