go backsqlschool blogs list

Πώς εκτελείται λογικά ένα sql query;

by Antonios Chatzipavlis

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

Όλοι λίγο ή πολύ έχετε γράψει ένα sql query. Άλλες φορές αυτό λειτούργησε άψογα άλλες φορές όχι. Το μυστικό για να γράψεις ένα καλό sql query είναι να έχεις κατανοήσει πως αυτό λογικά εκτελείται, ιδιαίτερα στην μηχανή που χρησιμοποιείς, στην δικιά μας περίπτωση ο SQL Server.

Ένα sql query περιέχει κάποιες εκφράσεις μέσα του, εδώ θα ασχοληθούμε με τι βασικές, Έτσι ένα sql query είναι της μορφής αυτής. Στους αριθμούς μέσα στις παρενθέσεις φαίνεται η σειρά, βήμα, φάση εκτέλεσης.

Κάθε βήμα δημιουργεί έναν virtual table ο οποίος είναι το input για το επόμενο βήμα. Αυτά το virtual tables δεν είναι διαθέσιμα σε κανένα πλήν του SQL Server, εκτός του τελευταίου που είναι και αυτό που παίρνουμε σαν απάντηση. Εάν στο sql query μας δεν έχουμε κάποια έκφραση απλά αυτή αγνοείτε και πάει στο επόμενο βήμα.

 

(8) SELECT (9) DISTINCT (11) <TOP_specification> <select_list>

(1) FROM <left_table>

(3) <join_type> JOIN <right_table>

(2) ON <join_condition>

(4) WHERE <where_condition>

(5) GROUP BY <group_by_list>

(6) WITH {CUBE | ROLLUP}

(7) HAVING <having_condition>

(10) ORDER BY <order_by_list>

 

Ας δούμε τα πράγματα λίγο αναλυτικά με ένα παράδειγμα που θα δημιουργήσουμε με το παρακάτω script

SET NOCOUNT ON;

USE tempdb;

GO

IF OBJECT_ID('dbo.Orders') IS NOT NULL

DROP TABLE dbo.Orders;

GO

IF OBJECT_ID('dbo.Customers') IS NOT NULL

DROP TABLE dbo.Customers;

GO

CREATE TABLE dbo.Customers

(

customerid CHAR(5) NOT NULL PRIMARY KEY,

city VARCHAR(10) NOT NULL

);

 

INSERT INTO dbo.Customers(customerid, city) VALUES('ANTON', 'Athens');

INSERT INTO dbo.Customers(customerid, city) VALUES('NASOS', 'Athens');

INSERT INTO dbo.Customers(customerid, city) VALUES('FANIS', 'Athens');

INSERT INTO dbo.Customers(customerid, city) VALUES('CHRIS', 'Salonica');

 

CREATE TABLE dbo.Orders

(

orderid INT NOT NULL PRIMARY KEY,

customerid CHAR(5) NULL REFERENCES Customers(customerid)

);

 

INSERT INTO dbo.Orders(orderid, customerid) VALUES(1, 'NASOS');

INSERT INTO dbo.Orders(orderid, customerid) VALUES(2, 'NASOS');

INSERT INTO dbo.Orders(orderid, customerid) VALUES(3, 'FANIS');

INSERT INTO dbo.Orders(orderid, customerid) VALUES(4, 'FANIS');

INSERT INTO dbo.Orders(orderid, customerid) VALUES(5, 'FANIS');

INSERT INTO dbo.Orders(orderid, customerid) VALUES(6, 'CHRIS');

INSERT INTO dbo.Orders(orderid, customerid) VALUES(7, NULL);

Μετά από την εκτέλεση του θα έχουμε δύο πίνακες τους Customers, Orders οι οποίοι είναι related μεταξύ τους και τα δεδομένα τους θα είναι τα εξής

Customers Table Data

customerid

city

ANTON

Athens

CHRIS

Salonica

FANIS

Athens

NASOS

Athens

 

Orders Table Data

Orderid

customerid

1

NASOS

2

NASOS

3

FANIS

4

FANIS

5

FANIS

6

CHRIS

7

NULL

 

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

Έτσι το sql query μας θα είναι σαν αυτό.

SELECT C.customerid, COUNT(O.orderid) AS numorders

FROM dbo.Customers AS C

LEFT OUTER JOIN dbo.Orders AS O

ON C.customerid = O.customerid

WHERE C.city = 'Athens'

GROUP BY C.customerid

HAVING COUNT(O.orderid) < 3

ORDER BY numorders;

Το αποτέλεσμα της εκτέλεσης του είναι το παρακάτω

Customerid

numorders

ANTON

0

NASOS

2

 

Ποιά είναι όμως η λογική του εκτέλεση; Ας δούμε λοιπόν τα βήματα της εκτέλεσης.

Βήμα 1ο - Cross Join

FROM dbo.Customers AS C ... JOIN dbo.Orders AS O

 

Εδώ φτιάχνει το καρτεσιανό γινόμενο των δύο πινάκων και το βάζει στο 1ο virtual table (VT1). Το περιεχόμενο του πίνακα αυτού είναι 28 γραμμές ( 4x7).

Customerid

City

Orderid

customerid

ANTON

Athens

1

NASOS

ANTON

Athens

2

NASOS

ANTON

Athens

3

FANIS

ANTON

Athens

4

FANIS

ANTON

Athens

5

FANIS

ANTON

Athens

6

CHRIS

ANTON

Athens

7

NULL

CHRIS

Salonica

1

NASOS

CHRIS

Salonica

2

NASOS

CHRIS

Salonica

3

FANIS

CHRIS

Salonica

4

FANIS

CHRIS

Salonica

5

FANIS

CHRIS

Salonica

6

CHRIS

CHRIS

Salonica

7

NULL

FANIS

Athens

1

NASOS

FANIS

Athens

2

NASOS

FANIS

Athens

3

FANIS

FANIS

Athens

4

FANIS

FANIS

Athens

5

FANIS

FANIS

Athens

6

CHRIS

FANIS

Athens

7

NULL

NASOS

Athens

1

NASOS

NASOS

Athens

2

NASOS

NASOS

Athens

3

FANIS

NASOS

Athens

4

FANIS

NASOS

Athens

5

FANIS

NASOS

Athens

6

CHRIS

NASOS

Athens

7

NULL

 

Βήμα 2ο - Apply Join condition ON Filter

ON C.customerid = O.customerid

Στο βήμα αυτό εφαρμόζεται το ON που υπάρχει στο Join και μόνο τα rows εκείνα τα οποία ικανοποιούν το βήμα πηγαίνουν στον VT2 που θα είναι το αποτέλεσμα του βήματος αυτού.

Έτσι αν πάρω τον VT1 και εφαρμόσω στο παράδειγμα μας το ON θα έχω το εξής αποτέλεσμα

Customerid

City

Orderid

customerid

ΟΝ Filter

ANTON

Athens

1

NASOS

FALSE

ANTON

Athens

2

NASOS

FALSE

ANTON

Athens

3

FANIS

FALSE

ANTON

Athens

4

FANIS

FALSE

ANTON

Athens

5

FANIS

FALSE

ANTON

Athens

6

CHRIS

FALSE

ANTON

Athens

7

NULL

UNKNOWN

CHRIS

Salonica

1

NASOS

FALSE

CHRIS

Salonica

2

NASOS

FALSE

CHRIS

Salonica

3

FANIS

FALSE

CHRIS

Salonica

4

FANIS

FALSE

CHRIS

Salonica

5

FANIS

FALSE

CHRIS

Salonica

6

CHRIS

TRUE

CHRIS

Salonica

7

NULL

UNKNOWN

FANIS

Athens

1

NASOS

FALSE

FANIS

Athens

2

NASOS

FALSE

FANIS

Athens

3

FANIS

TRUE

FANIS

Athens

4

FANIS

TRUE

FANIS

Athens

5

FANIS

TRUE

FANIS

Athens

6

CHRIS

FALSE

FANIS

Athens

7

NULL

UNKNOWN

NASOS

Athens

1

NASOS

TRUE

NASOS

Athens

2

NASOS

TRUE

NASOS

Athens

3

FANIS

FALSE

NASOS

Athens

4

FANIS

FALSE

NASOS

Athens

5

FANIS

FALSE

NASOS

Athens

6

CHRIS

FALSE

NASOS

Athens

7

NULL

UNKNOWN

 

Δηλαδή ο VT2 θα είναι τελικά ο παρακάτω

Customerid

City

Orderid

customerid

CHRIS

Salonica

6

CHRIS

FANIS

Athens

3

FANIS

FANIS

Athens

4

FANIS

FANIS

Athens

5

FANIS

NASOS

Athens

1

NASOS

NASOS

Athens

2

NASOS

 

Βήμα 3ο - Apply OUTER Join

FROM dbo.Customers AS C LEFT OUTER JOIN dbo.Orders AS O

Στην περίπτωση μας μόνο ένας είναι ο πελάτης από την πίνακα τον πελατών που δεν υπάρχει στον VT2 o ΑΝΤΟΝ οπότε μπαίνει και αυτό στον VT3 που είναι το αποτέλεσμα του βήματος αυτού

Customerid

City

Orderid

customerid

CHRIS

Salonica

6

CHRIS

FANIS

Athens

3

FANIS

FANIS

Athens

4

FANIS

FANIS

Athens

5

FANIS

NASOS

Athens

1

NASOS

NASOS

Athens

2

NASOS

ΑΝΤΟΝ

Athens

NULL

NULL

 

Βήμα 4ο - Apply WHERE filter

WHERE C.city = 'Athens'

Το αποτέλεσμα είναι ο VT4

Customerid

City

Orderid

customerid

FANIS

Athens

3

FANIS

FANIS

Athens

4

FANIS

FANIS

Athens

5

FANIS

NASOS

Athens

1

NASOS

NASOS

Athens

2

NASOS

ΑΝΤΟΝ

Athens

NULL

NULL

 

Βήμα 5ο - Apply Grouping

GROUP BY C.customerid

Το αποτέλεσμα είναι ο VT5

Customerid

City

Orderid

customerid

FANIS

Athens

3

FANIS

FANIS

Athens

4

FANIS

FANIS

Athens

5

FANIS

NASOS

Athens

1

NASOS

NASOS

Athens

2

NASOS

ΑΝΤΟΝ

Athens

NULL

NULL

 

Βήμα 6ο - Apply Cube or Rollup

Δεν έχουμε κάτι τέτοιο στο query μας οπότε πάει στο επόμενο βήμα.

Βήμα 7ο - Apply HAVING Filter

HAVING COUNT(O.orderid) < 3

Το αποτέλεσμα είναι ο VT7

Customerid

City

Orderid

customerid

NASOS

Athens

1

NASOS

NASOS

Athens

2

NASOS

ΑΝΤΟΝ

Athens

NULL

NULL

 

Βήμα 8ο - Apply SELECT List

SELECT C.customerid, COUNT(O.orderid) AS numorders

Το αποτέλεσμα είναι ο VT8

Customerid

numorders

NASOS

2

ANTON

0

Βήμα 9ο - Apply DISTINCT

Δεν έχουμε κάτι τέτοιο στο query μας οπότε πάει στο επόμενο βήμα.

Βήμα 10ο - Apply ORDER BY

SELECT C.customerid, COUNT(O.orderid) AS numorders

Το αποτέλεσμα είναι ο VT10

Customerid

numorders

ANTON

0

NASOS

2

Βήμα 11ο - Apply TOP

Δεν έχουμε κάτι τέτοιο στο query μας οπότε καταλήγουμε στο τελικό μας αποτέλεσμα.

ΥΓ. Επίτηδες παρέλειψα κάποια βήματα για να μην σας κουράσω. Αν υπάρχει απαίτηση από εσάς μέσω των σχολίων σας θα προχωρήσω βαθύτερα και σε αυτά

Ημερομηνία: 26 August 2009 14:23
Αξιολόγηση:
Tags:
Share it:

Αφήστε το σχόλιο σας - Leave your comment

Τα σχόλια έχουν κλείσει.
Επιτρέπονται μόνο τα σχόλια από τα μέλη του SqlSchool.gr.


newsletter subscription

Εάν επιθυμείτε να λαμβάνετε ενημέρωση από εμάς, δώστε μας το e-mail σας.
PASS chapter logo
Official Professional Association for SQL Server (PASS) chapter for Greece
Join to PASS