Reputation: 832
I am occasionally forced to use MS-SQL, so my knowledge of it is basic. I'm sure the following problem is piece of cake for an MS-SQL expert, but for me this looks really like a nasty bug:
Say I have a simple table containing a person's last name, first name, and email, like this:
CREATE TABLE dbo.people
(
lastName varchar(50) NULL,
firstName varchar(50) NULL,
email varchar(50) NULL
)
Now I'm going to create a view so I have some pre-concated fields, like this:
CREATE VIEW v_people AS
SELECT
people.*,
people.lastName + ' ' + people.firstName AS concatName
FROM people
Now I notice that I forgot the Phone number field, and alter the original table, but ONLY the table, NOT the view:
ALTER TABLE dbo.people ADD
phone varchar(50) NULL
Cool, also works. But what now happened to the view is quite horrible: The view field 'concatName' does not contain the concated names, but the Phone Numbers, even if the view fields are STILL the same amount and names!
It seems that MS-SQL is just moving the data columns within the view without updating the column definitions. Quite horrible scenario, if you forget to update views that depends on tables you alter...
Do I have overseen something, or am I really responsible for always checking / altering all the views if I just add a new table column? Is there a way to let the MS-SQL server at least throw a warning about depending views?
I noticed that it does not happen if the view is constructed like this:
CREATE VIEW v_people AS
SELECT
people.lastName + ' ' + people.firstName AS concatName,
people.*
FROM people
But for me this just looks like a nasty workaround....
Any hints?
Upvotes: 4
Views: 3424
Reputation: 311
As already answered years ago, the solution is to use sp_refreshview 'YourView'
for the affected views.
Since one of the follow-up questions was if you need to do it for each view manually afterwards, I want to answer that: You could search for views that have a * in their definition (surrounded by SELECT and FROM) by using sys.sql_modules
.
SELECT schemas.name 'schema',
objects.name 'object',
sql_modules.definition 'definition'
FROM sys.sql_modules
JOIN sys.objects ON sql_modules.object_id=objects.object_id
JOIN sys.schemas ON objects.schema_id=schemas.schema_id
WHERE definition LIKE '%SELECT%*%FROM%'
AND objects.type = 'V'
ORDER BY schemas.name, objects.name
You can now take that and iterate over them using a cursor.
DECLARE db_cursor CURSOR FOR
SELECT TOP 10 schemas.name + '.' + objects.name 'View'
FROM sys.sql_modules
JOIN sys.objects ON sql_modules.object_id=objects.object_id
JOIN sys.schemas ON objects.schema_id=schemas.schema_id
WHERE definition LIKE '%SELECT%*%FROM%'
AND objects.type = 'V'
ORDER BY schemas.name, objects.name
DECLARE @View VARCHAR(128)
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @View
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC sp_refreshview @View
FETCH NEXT FROM db_cursor INTO @View
END
Upvotes: 0
Reputation: 65147
As Martin mentions, you need to refresh the view if you change the definition of the underlying table and use SELECT *
in your view.
A really easy way to avoid this is to NEVER USE SELECT *
in your views!
It's a terrible practice and can cause all sorts of issues. The only "benefit" is that you don't need to type out field names the ONE TIME you define the view.
Upvotes: 2
Reputation: 453028
You need to call sp_refreshview 'YourView'
after altering the definition of tables selected from with *
.
Upvotes: 9