04 - SQL (μέρος 2)

23
Βάσεις Δεδομένων Ι - 04 SQL – Μέρος 2 ο Φώτης Κόκκορας (MSc/PhD) Τμήμα Μηχανικών Πληροφορικής ΤΕ ΤΕΙ Θεσσαλίας

description

Θεωρία και παραδείγματα σε SQL (μέρος 2). Ερωτήματα Πολλαπλών Σχέσεων, Υποερωτήματα, IN, EXISTS, ALL, ANY, Συγκεντρωτικοί Υπολογισμοί, GROUP BY, HAVING DATABASE: https://dl.dropboxusercontent.com/u/2690181/myBeersDB.zip

Transcript of 04 - SQL (μέρος 2)

Page 1: 04 - SQL (μέρος 2)

Βάσεις Δεδομένων Ι - 04

SQL – Μέρος 2ο

Φώτης Κόκκορας (MSc/PhD) Τμήμα Μηχανικών Πληροφορικής ΤΕ ΤΕΙ Θεσσαλίας

Page 2: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 2 - Βάσεις Δεδομένων Ι

Ερωτήματα Πολλαπλών Σχέσεων (multi-relation queries)

Θα διαπιστώσετε στην πορεία ότι τα περισσότερο ενδιαφέροντα ερωτήματα είναι

αυτά που εμπλέκουν πολλές σχέσεις (πίνακες).

Η εμπλοκή πολλών πινάκων σε ένα ερώτημα γίνεται παραθέτοντας τα ονόματά τους

στο FROM τμήμα του ερωτήματος.

Παράδειγμα:

έστω οι σχέσεις: Likes(drinker, beer) και Frequents(drinker, bar)

και το ερώτημα: "ποιες μπύρες αρέσουν στα άτομα που συχνάζουν στο bar A.P. Stump's"; SELECT beer FROM Frequents, Likes

WHERE bar = 'A.P. Stump\'s' AND Frequents.drinker = Likes.drinker;

υπενθυμίζεται ότι τα εσωτερικά μονά quotes σε αλφαριθμητικά στον MySQL

Server πρέπει να μπαίνουν escaped, δηλαδή να προηγείται ο χαρακτήρας \

Προσέξτε ότι ξεχωρίζουμε τα γνωρίσματα με ίδιο όνομα (στο παράδειγμα,

το drinker) βάζοντας μπροστά το όνομα της σχέσης (του πίνακα), π.χ. Likes.drinker

Πώς ακριβώς υπολογίζεται η απάντηση στο παραπάνω ερώτημα;

Page 3: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 3 - Βάσεις Δεδομένων Ι

Γινόμενο Σχέσεων (περισσότερα όταν μιλήσουμε για Σχεσιακή Άλγεβρα)

Πρώτα θα δούμε την έννοια του γινομένου (product) σχέσεων. Έστω οι

σχέσεις R1 και R2. Το γινόμενο των R1 και R2 είναι μια σχέση R3 = R1xR2 με:

πλειάδες που προκύπτουν αν συνδυάσουμε κάθε πλειάδα της σχέσης R1 με

κάθε πλειάδα της σχέσης R2

σχήμα (schema) που προκύπτει από την συνένωση των επιμέρους σχημάτων των

R1 και R2, με αυτή όμως τη σειρά

Σημείωση: αν υπάρχουν γνωρίσματα με ίδιο όνομα, βάζουμε μπροστά το όνομα της σχέσης.

Παράδειγμα:

Page 4: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 4 - Βάσεις Δεδομένων Ι

Ερωτήματα Πολλαπλών Σχέσεων (συνέχεια)

SELECT beer FROM Frequents, Likes

WHERE bar = 'A.P. Stump\'s' AND Frequents.drinker = Likes.drinker;

Φανταστείτε 2 πλειάδες-μεταβλητές t1 και t2 (μία για κάθε σχέση). Αυτές επισκέ-

πτονται κάθε συνδυασμό που προκύπτει παίρνοντας μια πλειάδα από κάθε σχέση.

Αν οι t1 και t2 δείχνουν σε πλειάδες που ικανοποιούν τους περιορισμούς που

θέτει το WHERE τμήμα του ερωτήματος, τότε από αυτές τις πλειάδες παίρνουμε την

πληροφορία που ορίζει το SELECT τμήμα του ερωτήματος.

Page 5: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 5 - Βάσεις Δεδομένων Ι

Ρητή Χρήση Μεταβλητών Μερικές φορές κάποιο ερώτημα πρέπει να χρησιμοποιήσει δύο φορές την ίδια σχέση!

πρέπει κάπως να ξεχωρίζει σε ποια σχέση από τις δύο ανήκουν τα διάφορα πεδία

Δουλεύουμε ως εξής:

στα ονόματα των σχέσεων στο FROM τμήμα, ορίζουμε μεταβλητές για κάθε σχέση

πρακτικά, αλλάζουμε όνομα στις σχέσεις!!!

στα ονόματα των πεδίων στο SELECT τμήμα χρησιμοποιούμε αυτές τις μεταβλητές

Παράδειγμα:

Στη σχέση Beers(name, manf), θέλουμε να βρούμε όλα τα ζευγάρια μπύρας του ίδιου

κατασκευαστή, χωρίς όμως:

να παράγονται ζευγάρια ίδιας μπύρας όπως (Budweiser, Budweiser) και επιπλέον,

η πρώτη μπύρα στο ζευγάρι να προηγείται αλφαβητικά της δεύτερης

π.χ. δεκτό το (Budweiser, Creamy Dark) αλλά όχι το (Creamy Dark, Budweiser)

SELECT b1.name, b2.name

FROM Beers b1, Beers b2

WHERE b1.manf = b2.manf AND b1.name < b2.name;

Σημείωση: η ανισότητα με αλφαριθμητικά πρακτικά ελέγχει

αν το b1.name προηγείται αλφαβητικά έναντι του b2.name.

Page 6: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 6 - Βάσεις Δεδομένων Ι

Υποερωτήματα (Subqueries)

Ένα ερώτημα SELECT-FROM-WHERE μπορεί να χρησιμοποιηθεί (μέσα σε παρενθέσεις)

ως τιμή σε μια σειρά θέσεων (όπως στο FROM και το WHERE) μέσα σε άλλο ερώτημα.

Δηλαδή, αντί να βάλουμε μια σχέση μετά από μια δήλωση FROM, μπορούμε να

βάλουμε ένα υποερώτημα (σε παρενθέσεις) και πρακτικά να κάνουμε την

ερώτηση πάνω στα αποτελέσματα του υποερωτήματος!

Αυτό είναι και τεχνικά αποδεκτό καθώς το αποτέλεσμα ενός SELECT ερωτήματος

είναι το ίδιο μια σχέση!

Παράδειγμα: "Βρες τις μπύρες που αρέσουν στα άτομα που

συχνάζουν στο bar Caravan".

SELECT beer

FROM Likes, ( SELECT drinker FROM Frequents

WHERE bar = 'Caravan') CaravanDrinker

WHERE Likes.drinker = CaravanDrinker.drinker;

Σημείωση: Χρειάστηκε να ορίσουμε πλειάδα-μεταβλητή (CaravanDrinker) για να

αναφερθούμε στα αποτελέσματα του υποερωτήματος.

Άρα το υποερώτημα (σε κίτρινο φόντο παραπάνω) "μαζεύει" τους πελάτες που συχνάζουν

στο bar Caravan.

Page 7: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 7 - Βάσεις Δεδομένων Ι

Υποερωτήματα που επιστρέφουν μια τιμή!

Αν ένα υποερώτημα εγγυημένα επιστρέφει μία μόνο πλειάδα μιας στήλης, τότε

αυτό το υποερώτημα μπορεί να χρησιμοποιηθεί ως τιμή (value) σε κάποια σχετική

θέση μέσα σε άλλο ερώτημα.

Αν το υποερώτημα δεν επιστρέψει ακριβώς μία πλειάδα μιας στήλης, προκύπτει σφάλμα

(run-time-error).

Παράδειγμα: Μέσω της σχέσης Sells(bar, beer, price), βρες τα bar που πουλάνε

τη μπύρα Hefeweizen στην ίδια τιμή που το bar Blue Tattoo χρεώνει την Killian's.

Τα παρακάτω δύο ερωτήματα σίγουρα δουλεύουν:

Βρες πόσο χρεώνει το Blue Tattoo για την μπύρα Killian's.

SELECT price FROM Sells WHERE bar='Blue Tattoo' AND beer='Killian\'s';

Βρες τα bar που χρεώνουν το ίδιο ποσό για την μπύρα Hefeweizen.

SELECT bar FROM Sells WHERE beer='Hefeweizen' AND price=6;

Συνδυασμός σε μια ερώτηση με χρήση υποερωτήματος:

SELECT bar FROM Sells

WHERE beer='Hefeweizen' AND price = ( SELECT price FROM Sells

WHERE bar='Blue Tattoo' AND

beer='Killian\'s' ); Η εξίσωση price = (υποερώτημα) είναι

αποδεκτή γιατί το υποερώτημα επιστρέφει

ΜΙΑ ΜΟΝΟ τιμή (στο παράδειγμα, το 6).

Page 8: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 8 - Βάσεις Δεδομένων Ι

Ο Τελεστής ΙΝ (ξανά!)

Με τον τελεστή ΙΝ έχουμε πει ότι μπορούμε να ορίσουμε εύκολα μια συνθήκη για τις

τιμές που θέλουμε/επιτρέπουμε να πάρει ένα πεδίο: SELECT name, city FROM Bars WHERE city IN ('Chicago', 'New York');

στα αποτελέσματα, το city θα είναι είτε Chicago ή New York

Στην πραγματικότητα το ('Chicago', 'New York') είναι μια σχέση με δύο πλειάδες!

ΑΡΑ αυτό που ακολουθεί το IN (ή το NOT IN) είναι μια σχέση (πίνακας!).

ΑΡΑ μπορούμε στη θέση του ('Chicago', 'New York') να βάλουμε

ακόμη και ένα υποερώτημα! (που ως γνωστό επιστρέφει πίνακα!)

Παράδειγμα: Βρες την μπύρα και τον κατασκευαστή της

για όσες μπύρες αρέσουν στον John.

SELECT * FROM Beers

WHERE name IN ( SELECT beer FROM Likes

WHERE drinker = 'John' );

Οι μπύρες που αρέσουν στον John.

Page 9: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 9 - Βάσεις Δεδομένων Ι

Ο τελεστής EXISTS (υπάρχει) Σημείωση: τα υποερωτήματα επιστρέφουν πλειάδες με μια μόνο στήλη.

Η εντολή EXISTS(<υποερώτημα>) επιστρέφει TRUE αν και μόνο αν το υποερώτημα

επιστρέφει τουλάχιστον ένα αποτέλεσμα.

Με απλά λόγια: επιστρέφει TRUE αν υπάρχει (exists) αποτέλεσμα στο υποερώτημα.

Μπορεί να χρησιμοποιηθεί και με NOT μπροστά (βλ. παράδειγμα), οπότε τότε επιστρέφει

TRUE αν δεν υπάρχει (NOT EXISTS) αποτέλεσμα στο υποερώτημα.

Παράδειγμα: Από τη σχέση Beers(name, manf), βρες τις μπύρες που

είναι οι μοναδικές που φτιάχνει ο κατασκευαστής τους!

Σημείωση: Για να πάρετε αποτέλεσμα από τη myBeersDB, καταχωρήστε

στη σχέση Beers την ('Amstel','Αθηναϊκή'). (διαγράψτε την μετά το παράδειγμα)

SELECT name FROM Beers b1

WHERE NOT EXISTS ( SELECT * FROM Beers

WHERE manf = b1.manf AND name <> b1.name );

Αυτό το manf ανήκει στην σχέση που βρίσκεται στο

πλησιέστερο υποερώτημα, δηλ. στο Beers του υποερω-

τήματος και όχι το Beers του εξωτερικού ερωτήματος!

Για αποφυγή σύγχυσης στα name, ορίσαμε τη

μεταβλητή b1 για τον εξωτερικό πίνακα Beers.

Μπύρες με τον ίδιο κατασκευαστή

(manf) όπως η μπύρα b1.name

αλλά διαφορετικές από αυτή!

Page 10: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 10 - Βάσεις Δεδομένων Ι

Ο τελεστής ALL

Σημείωση: τα υποερωτήματα επιστρέφουν πλειάδες με μια μόνο στήλη.

Η φράση x <> ALL(<subquery>) είναι αληθής (TRUE) αν και μόνο αν, για κάθε

πλειάδα t της σχέσης που ορίζει το υποερώτημα, το x είναι διάφορο του t.

με απλά λόγια: το x δεν βρίσκεται μέσα στα αποτελέσματα του υποερωτήματος!

Δηλαδή, το <>ALL είναι ισοδύναμο με το NOT IN

Αντί για <> μπορούμε να έχουμε άλλο τελεστή σύγκρισης (με ανάλογη ερμηνεία!).

Παράδειγμα: x >= ALL(<subquery>) είναι TRUE αν το x είναι μεγαλύτερο ή ίσο από όλα

(ALL) τα αποτελέσματα του υποερωτήματος.

Παράδειγμα: Με τον πίνακα Sells(bar,beer,price), βρες τις

μπύρες με την υψηλότερη τιμή!

SELECT beer FROM Sells

WHERE price >= ALL( SELECT price FROM Sells );

Τελικά ποια είναι η ακριβότερη

μπύρα στην myBeersDB;

Στο bar Hedley Club η μπύρα

Hefeweizen κοστίζει 8.00 $.

Η τιμή από την εξωτερική σχέση

Sells, πρέπει να είναι μεγαλύτερη

ή ίση από κάθε άλλη τιμή!

Page 11: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 11 - Βάσεις Δεδομένων Ι

Ο τελεστής ΑΝΥ

Σημείωση: τα υποερωτήματα επιστρέφουν πλειάδες με μια μόνο στήλη (πεδίο).

Η φράση x = ANY(<subquery>) επιστρέφει TRUE αν και μόνο αν υπάρχει κατ'ελάχιστο

μια πλειάδα στο subquery με την οποία ισούται το x.

Δηλαδή, για τον τελεστή = η ερμηνεία του ANY είναι ίδια με αυτή του IN στην

εκδοχή που είδαμε στο slide #8:

SELECT ... FROM ... WHERE x = ANY (SELECT ... FROM ...);

SELECT ... FROM ... WHERE x IN (SELECT ... FROM ...);

Αντί για = μπορεί να έχουμε οποιοδήποτε τελεστή σύγκρισης!

Παράδειγμα: το x >= ANY(<subquery>) σημαίνει ότι το x είναι μεγαλύτερο ή ίσο από

τουλάχιστον μια εγγραφή του υποερωτήματος.

Οι τελεστές ALL και ANY είναι εξειδικεύσεις του τελεστή EXISTS. Το

αποτέλεσμά τους μπορεί να παραχθεί με χρήση του τελεστή

EXISTS και κατάλληλη διαμόρφωση του υποερωτήματος.

Page 12: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 12 - Βάσεις Δεδομένων Ι

Ένωση – Τομή – Διαφορά UNION – INTERSECT – EXCEPT

H ένωση/union, η τομή/intersection και η διαφορά/difference σχέσεων εκφράζονται

με τους ακόλουθους τρόπους (εννοείται με χρήση υποερωτημάτων):

(<subquery>) UNION (<subquery>)

(<subquery>) INTERSECT (<subquery>)

(<subquery>) EXCEPT (<subquery>)

Παράδειγμα με INTERSECT (δεν υποστηρίζεται σε MySQL)

Μέσω των σχέσεων Likes(drinker,beer), Sells(bar,beer,price) και

Frequents(drinker,bar), βρες τους πελάτες και τις μπύρες που:

στον πελάτη αρέσει η μπύρα

ο πελάτης συχνάζει σε τουλάχιστον ένα bar που πουλάει αυτή τη μπύρα

(SELECT * FROM Likes) INTERSECT ( SELECT drinker, beer

FROM Sells, Frequents

WHERE Frequents.bar=Sells.bar );

Ο MySQL server υποστηρίζει μόνο την ένωση/union σχέσεων.

Page 13: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 13 - Βάσεις Δεδομένων Ι

Παράδειγμα UNION σε MySQL

(SELECT * FROM Likes WHERE drinker='Jesse')

UNION

(SELECT drinker, beer FROM Sells, Frequents

WHERE Frequents.bar=Sells.bar AND drinker='Jesse');

Το πρώτο υποερώτημα, μόνο του, επιστρέφει:

Το δεύτερο υποερώτημα, μόνο του, επιστρέφει:

Συνολικά το παραπάνω ερώτημα επιστρέφει:

Οι πολλαπλές απαντήσεις (πλειάδες) προφανώς απαλείφονται. Αν τις θέλουμε όλες, αντί για

UNION βάζουμε UNION ALL.

Προσέξτε ότι τα δύο υποερωτήματα πρέπει να επιστρέφουν σχέσεις ίδιου σχήματος

(drinker,beer), διαφορετικά δεν έχει νόημα το UNION (όμοια τα INTERSECT, EXCEPT)

Page 14: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 14 - Βάσεις Δεδομένων Ι

Συγκεντρωτικοί Υπολογισμοί (Aggregations) Οι ακόλουθες συναρτήσεις εφαρμόζονται σε μια στήλη στο SELECT τμήμα ερωτήμα-

τος και κάνουν τον υπολογισμό πάνω σε όλα τα αποτελέσματα του ερωτήματος:

COUNT (καταμέτρηση)

Πόσες μπύρες είναι καταχωρημένες στον beers; (Απάντηση: 20)

SELECT COUNT(*) FROM beers;

Σε πόσες διαφορετικές τιμές πωλείται η Budweiser; (Απάντηση: 7)

SELECT COUNT(DISTINCT price) FROM Sells WHERE beer = 'Budweiser';

SUM (άθροισμα)

Πόσο κοστίζει να πιούμε όλες τις μάρκες μπύρας που σερβίρει το bar Caravan; (Απάντηση:9)

SELECT sum(price) FROM sells where bar='Caravan';

AVG (μέσος όρος - average)

Ποια η μέση τιμή της Budweiser; (Απάντηση: 4.472222)

SELECT avg(price) FROM sells WHERE beer='Budweiser';

min (ελάχιστη τιμή – με μικρούς χαρακτήρες σε MySQL)

Ποια η τιμή της φθηνότερης μπύρας; (Απάντηση: 2.5)

SELECT min(price) FROM sells;

max (μέγιστη τιμή – με μικρούς χαρακτήρες σε MySQL)

Ποια η τιμή της ακριβότερης μπύρας; (Απάντηση: 8)

SELECT max(price) FROM sells;

Page 15: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 15 - Βάσεις Δεδομένων Ι

Ερμηνεία Συγκεντρωτικού Υπολογισμού με ΜΙΑ μόνο στήλη στο SELECT

Έστω το ερώτημα: Ποια η μέση τιμή της Budweiser;

SELECT avg(price) FROM sells WHERE beer='Budweiser';

Σκεφτείτε το ίδιο ερώτημα χωρίς το συγκεντρωτικό υπολογισμό:

SELECT price

FROM sells

WHERE beer='Budweiser';

Τα αποτελέσματα φαίνονται στην αριστερή εικόνα.

Όταν όμως γίνεται χρήση της συνάρτησης avg, τότε πάνω σε αυτά

τα αποτελέσματα εκτελείται μέσος όρος και επιστρέφεται αυτό ως

αποτέλεσμα (δεξιά εικόνα).

Στην περίπτωση που στο SELECT υπάρχουν περισσότερες στήλες, τα πράγματα είναι

πιο πολύπλοκα και απαιτείται η χρήση του τελεστή ομαδοποίησης GROUP BY.

Θα το δούμε αναλυτικά παρακάτω.

Page 16: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 16 - Βάσεις Δεδομένων Ι

Συγκεντρωτικές Πράξεις και NULL

Οι τιμές NULL αγνοούνται στους συγκεντρωτικούς υπολογισμούς COUNT, SUM και AVG,

ενώ δεν μπορεί να είναι το min ή το max μιας στήλης!

Αν όμως σε μια στήλη υπάρχουν μόνο NULL τιμές (ή δεν υπάρχουν καθόλου τιμές!)

τότε το αποτέλεσμα ενός συγκεντρωτικού υπολογισμού είναι NULL, εκτός της

καταμέτρησης (COUNT) που όπως είναι λογικό θα επιστρέψει μηδέν (0).

Παραδείγματα:

Ποια η μεγαλύτερη τιμή πώλησης της μπύρας foo;

SELECT max(price) FROM sells WHERE beer='foo';

Απάντηση: null - δεν υπάρχει μπύρα foo!

Πόσα bar πουλάνε την μπύρα foo;

SELECT count(*) FROM sells WHERE beer='foo';

Απάντηση: 0 - κανένα μπαρ δεν πουλάει τη μπύρα foo

Page 17: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 17 - Βάσεις Δεδομένων Ι

Ομαδοποίηση (Grouping)

Είδαμε πιο πριν συγκεντρωτικές πράξεις σε ερώτημα με μία στήλη στο SELECT.

Όταν υπάρχουν περισσότερες στήλες, όσες είναι αριστερά της στήλης του

συγκεντρωτικού υπολογισμού πρέπει να ομαδοποιηθούν.

Για τη μέση τιμή πώλησης της μπύρας Budweiser είχαμε γράψει:

SELECT avg(price) FROM sells WHERE beer='Budweiser';

Τι γίνεται αν θέλουμε τη μέση τιμή πώλησης κάθε μπύρας;

Πώς θα προκύψει δηλαδή το αποτέλεσμα που απεικονίζεται δεξιά;

Βήμα 1: γράφουμε το ερώτημα που φέρνει τα δεδομένα (εδώ τις μπύρες

και τις τιμές τους από τον πίνακα Sells)

SELECT beer, price FROM sells

Βήμα 2: Βάζουμε συγκεντρωτικό υπολογισμό στη ζητούμενη στήλη και ομαδοποιούμε στις

στήλες αριστερά της:

SELECT beer, AVG(price) FROM Sells GROUP BY beer;

Τα παραπάνω βήματα έχουν ευρύτερη εφαρμογή:

Να βρείτε τη μέση τιμή μπύρας ανά πόλη

Page 18: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 18 - Βάσεις Δεδομένων Ι

Ερμηνεία Συγκεντρωτικού Υπολογισμού με ΠΟΛΛΕΣ στήλες στο SELECT

SELECT beer, AVG(price) FROM Sells GROUP BY beer;

Οι πλειάδες-αποτέλεσμα του ερωτήματος SELECT...FROM...WHERE, ομαδοποιούνται

με βάση την τιμή των πεδίων ομαδοποίησης (το

beer στο παράδειγμα) και μετά σε κάθε ομάδα,

εφαρμόζεται ο συγκεντρωτικός υπολογισμός που

ορίζεται στο SELECT.

Η εικόνα δεξιά απεικονίζει αυτό που πραγματικά γίνεται:

Το τελικό αποτέλεσμα απεικονίζεται στην κάτω εικόνα.

Page 19: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 19 - Βάσεις Δεδομένων Ι

Ομαδοποίηση – Παράδειγμα #2 Για κάθε πόλη και για κάθε μπαρ της πόλης, να υπολογιστεί πόσες μάρκες μπύρας

πουλά κάθε μπαρ και σε τι μέση τιμή.

SELECT city, bar, count(*) AS 'Πλήθος', avg(price)

FROM Bars, Sells WHERE name=bar

GROUP BY city, bar;

Ο πίνακας αριστερά δίνεται βοηθητικά για

να δείτε τα δεδομένα πριν την ομαδοποίηση

και τους συγκεντρωτικούς υπολογισμούς.

Page 20: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 20 - Βάσεις Δεδομένων Ι

Βασικός Κανόνας Ομαδοποίησης (για να κάνετε γρήγορα σωστές εκφράσεις)

Σε χρήση ομαδοποίησης, αν επιπλέον χρησιμοποιείται και κάποια συγκεντρωτική

συνάρτηση, τότε όλα τα πεδία που αναφέρονται στο SELECT, πρέπει:

είτε να βρίσκονται μέσα σε κάποια συνάρτηση συγκεντρωτικού υπολογισμού

ή να αναφέρονται στη λίστα πεδίων του GROUP BY

Στο παράδειγμα του προηγούμενου slide:

SELECT city, bar, count(*) AS 'Πλήθος', avg(price)

FROM Bars, Sells WHERE name=bar

GROUP BY city, bar;

Παρατηρήσεις:

στο SELECT παραπάνω υπάρχουν 4 στήλες (city, bar, πλήθος, μέση τιμή)

οι στήλες city, bar που είναι πριν από τις στήλες συγκεντρωτικού υπολογισμού

ομαδοποιούνται στο GROUP BY με την ίδια σειρά

επιτρέπεται η ταυτόχρονη χρήση περισσοτέρων συναρτήσεων

ομαδοποίησης στο τμήμα SELECT, εφόσον είναι επιθυμητό, αρκεί

να μην παραβιάζεται ο παραπάνω κανόνας.

Page 21: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 21 - Βάσεις Δεδομένων Ι

Δήλωση HAVING

Η δήλωση HAVING <condition> επιτρέπει να βάλουμε περιορισμούς στο

αποτέλεσμα συγκεντρωτικών πράξεων. Μπαίνει μετά τη δήλωση GROUP BY.

Παράδειγμα #1: στο ερώτημα του slide #18 έστω ότι θέλουμε να κρατήσουμε μόνο τις

μπύρες με μέση τιμή >5:

SELECT beer, AVG(price) AS avgPrice

FROM Sells

GROUP BY beer HAVING avgPrice > 5;

ορίσαμε νέο όνομα στο μέσο όρο με χρήση του AS - αλλιώς γράφουμε AVG(price)>5

ΠΡΟΣΟΧΗ: η συνθήκη εφαρμόζεται σε κάθε ομάδα που προκύπτει από την ομαδοποίηση και

όσες ομάδες δεν ικανοποιούν την συνθήκη απορρίπτονται!

Παράδειγμα #2: Να βρεθεί η μέση τιμή για τις μπύρες που είτε πωλούνται σε τουλάχιστον 4

μπαρ ή κατασκευάζονται από την εταιρία Anheuser-Busch.

SELECT beer, AVG(price) FROM Sells

GROUP BY beer HAVING COUNT(bar) >= 4 OR

beer IN ( SELECT name FROM Beers

WHERE manf = 'Anheuser-Busch' );

Page 22: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 22 - Βάσεις Δεδομένων Ι

Δήλωση HAVING (συνέχεια) Δείτε δύο διαφορετικές εκδοχές του παραδείγματος 2 (προηγούμενο slide), με ή

χωρίς φωλιασμένο ερώτημα. Τα ερωτήματα έχουν στοιχηθεί για εποπτικούς λόγους.

SELECT beer, AVG(price)

FROM Sells, Beers

WHERE beer=name

GROUP BY beer, manf

HAVING COUNT(bar) >= 4 OR

manf='Anheuser-Busch';

SELECT beer, AVG(price)

FROM Sells

GROUP BY beer

HAVING COUNT(bar) >= 4 OR

beer IN (SELECT name

FROM Beers

WHERE manf='Anheuser-Busch');

Σχόλια:

Όπως έχουμε ξαναδεί, η μή-χρήση φωλιασμένου ερωτήματος (αριστερά) εισάγει επιπλέον

πίνακα στο FROM και συνθήκη στο WHERE.

Μέσα στο HAVING (δεξιά) δεν μπορούμε να χρησιμοποιήσουμε το manf (όπως κάνουμε

αριστερά) διότι δεν υφίσταται τέτοια στήλη μετά τον συγκεντρωτικό υπολογισμό!

Έτσι, η χρήση φωλιασμένου ερωτήματος είναι μονόδρομος στη δεξιά προσέγγιση, πλην όμως η

αριστερή εκδοχή είναι απλούστερη και προκύπτει εντελώς μηχανικά, εφόσον έχει γίνει

κατανοητός ο μηχανισμός!

Page 23: 04 - SQL (μέρος 2)

Φ. Κόκκορας / Τμ. Μηχανικών Πληροφορικής ΤΕ / ΤΕΙ Θεσσαλίας - 23 - Βάσεις Δεδομένων Ι

Να δοκιμάσετε όλες τις εντολές στην database myBeersDB που σας δίνεται.

...