Θα ξεκινήσω με το disclaimer. Είναι γνωστό ότι τα implicit casts κρύβουν κινδύνους και ειδικά μέσα στα queries μας τα αποφεύγουμε. Παρόλα αυτά είναι καλό να ξέρουμε πως συμπεριφέρονται στον SQL Server και τι να περιμένουμε στο αποτέλεσμα.
Σε αυτό το post λοιπόν θα δούμε κάποιες περιπτώσεις που μπορεί να διαφύγουν σε κάποιον, να αποτελούν misconceptions ή κάποιος να περιμένει διαφορετική συμπεριφορά ειδικά αν σκέφτεται σε άλλη γλώσσα.
Για αρχή λοιπόν πρέπει κανείς να έχει στον νου του το data type precedence, το οποίο βρίσκει
εδώ
και μας δείχνει ποιος τύπος υπερισχύει όταν ένας operator προσπαθεί να συνδυάσει expressions διαφορετικού τύπου.
1) Numbers and strings
Αυτό που θα ήθελα να τονίσω και αποτελεί την πιο εύκολη πηγή λάθους είναι το πόσο κάτω πρέπει να σκρολλάρει κανείς τη λίστα για να φτάσει στους τύπους nvarchar, nchar, varchar, char. Αυτό σημαίνει ότι η πλειονότητα των άλλων τύπων, όταν συνδυάζεται με character string types θα υπερισχύσει.
Για παράδειγμα το expression
12 + '3'
δεν θα μας δώσει error ούτε θα επιστρέψει το string
'123',
αλλά θα επιστρέψει τον int 15. Αν ο δεύτερος operand δεν μετατρέπεται σε int πχ
12 + '3asdf' θα έχουμε error. Επίσης ο τύπος που υπερισχύει δεν έχει να κάνει ποτέ με την σειρά που εμφανίζονται, δηλαδή το
'12' + 3 θα κάνει επίσης
15
Το ίδιο ισχύει για όλους τους τύπους που είναι πάνω από το nvarchar.
2) NULL, ISNULL και COALESCE
Πριν από όλα θα ξεκαθαρίσω καλού κακού το εξής: το
SELECT CAST(NULL as int)
μας δίνει NULL, όπως και όταν έχουμε κάνει declare int variable που δεν έχει γίνει πουθενά initialize είναι NULL (όχι 0).
Από την άλλη τo SELECT CAST('' as int) δίνει 0 (όχι error, όχι null). H ISNULL συνάρτηση κοιτάει τον τύπο του πρώτου ορίσματος και αυτός θα είναι και το αποτέλεσμά της. Επομένως αν έχω το παρακάτω κομμάτι:
DECLARE @X int;
SELECT @Χ as X, ISNULL(@X,'') as Y;
Θα μου δώσει:
Και μιας που πιάσαμε το ISNULL θα ήθελα να επισημάνω την διαφορά που έχει από το COALESCE όταν δίνουμε ορίσματα διαφορετικού τύπου.
Παρακάτω βλέπουμε ότι για τα ίδια ορίσματα έχουμε διαφορετικό τύπου αποτέλεσμα:
DECLARE @X nvarchar(10) = NULL;
SELECT ISNULL(@X,42) as IsNullRes,
COALESCE(@X,42) as CoalesceRes
INTO #asdf;
EXEC tempdb..sp_columns #asdf;
COLUMN_NAME |
TYPE_NAME |
IsNullRes |
Nvarchar |
CoalesceRes |
Int |
Με βάση το documentation η ΙSNULL επιστρέφει τον τύπο του πρώτου ορίσματος, ενώ η COALESCE επιστρέφει τον ανώτερο τύπο.
Υ.Γ. Για όποιον θέλει να κάνει δοκιμές το SQL_VARIANT_PROPERTY(@x,'BaseType') είναι ένας εύκολος τρόπος να δει κανείς τον τύπο ενός expression.