Wildcards in CREATE VIEW statements
Fivi Panopoulou - Sotiris Karras
Σε αυτό το post θα μελετήσουμε τους κινδύνους που ελλοχεύουν στην χρήση του wildcard (*) στον ορισμό ενός view.
Για αρχή θα δημιουργήσουμε ένα view στην AdventureWorks με πληροφορίες για τα προϊόντα και τις κατηγορίες στις οποίες αυτά ανήκουν.
CREATE VIEW Production.vProductCategoryInfo
AS
SELECT p.Name as Product, ps.Name as Subcategory, pc.*, p.ListPrice
FROM Production.Product as p
INNER JOIN Production.ProductSubcategory AS ps
ON p.ProductSubcategoryID = ps.ProductSubcategoryID
INNER JOIN Production.ProductCategory as pc
ON ps.ProductCategoryID = pc.ProductCategoryID;
GO
SELECT *
FROM Production.vProductCategoryInfo;
GO
Το αποτέλεσμα είναι το παρακάτω:
Στην συνέχεια προσθέτουμε μια στήλη στον πίνακα ProductCategory, η οποία περιέχει τον χρήστη που δημιούργησε την κατηγορία και την κάνουμε populate
ALTER TABLE Production.ProductCategory
ADD ModifiedBy NVARCHAR(100) NULL;
GO
UPDATE Production.ProductCategory
SET ModifiedBy = N'fpan'
WHERE ProductCategoryId <= 2;
UPDATE Production.ProductCategory
SET ModifiedBy = N'sotkar'
WHERE ProductCategoryId > 2;
GO
SELECT * FROM Production.ProductCategory;
GO
Τώρα ο πίνακας των κατηγοριών έχει την παρακάτω μορφή:
Πάμε να δούμε τώρα τι θα γίνει αμα κάνουμε select από το αρχικό μας view, στο οποίο έχουμε ορίσει με το pc.* ότι θέλουμε όλες τις στήλες του ProductCategories. Αυτό που θα περιμέναμε να δούμε είναι το αρχικό αποτέλεσμα με μια ακόμη στήλη (την ModifiedBy) ανάμεσα στις δύο τελευταίες στήλες (ModifiedDate και ListPrice).
Το select στο view όμως επιστρέφει το παρακάτω result set:
Παρατηρούμε ότι αντί να προστεθεί μια στήλη όπως περιμέναμε, ο αριθμός των στηλών του view παραμένει ίδιος. Όμως παρατηρούμε πώς αντί για αυτό έχουν έρθει τα καινούρια δεδομένα και έχουν μπει στην τελευταία στήλη. Αυτό συμβαίνει γιατί ο SQL Server κρατάει για τα views metadata τα οποία δεν ανανεώνονται όταν γίνονται alter τα underlying objects, παρά μόνο αν το view έχει δημιουργηθεί με την επιλογή SCHEMABINDING.
Έτσι μια σκέψη θα ήταν, για να μην έχουμε αυτό το πρόβλημα, να δημιουργούμε όλα τα views με schemabinding. Αυτό όμως δεν γίνεται καθώς αν προσπαθήσουμε να ορίσουμε το ένα view το οποίο περιέχει στον ορισμό του *, όπως αυτό του παραδείγματός μας, ο SQL Server θα μας εμφανίσει το παρακάτω μήνυμα λάθους.
Για να αποφύγουμε αυτό το φαινόμενο θα πρέπει να αποφύγουμε εντελώς την χρήση του * στον ορισμό των views. Αν παρόλα αυτά έχουμε στην βάση μας τέτοια views, θα πρέπει να κάνουμε refresh τα metadata εκτελώντας την
sp_refreshview.
Για του λόγου το αληθές τρέχοντας το
exec sp_refreshview 'Production.vProductCategoryInfo';
GO
SELECT *
FROM Production.vProductCategoryInfo;
GO
το αποτέλεσμα είναι το αναμενόμενο: