The following is my code
IF NOT EXISTS (SELECT 1 FROM sys.objects o INNER JOIN sys.columns c ON o.object_id = c.object_id
WHERE
o.name = 'portfolioAttributeCodes'
AND c.name = 'isDisplayed'
)
BEGIN
ALTER TABLE
[cosmos].[portfolioAttributeCodes]
ADD
[isDisplayed] bit DEFAULT 1;
END
IF EXISTS (SELECT 1 FROM sys.objects o INNER JOIN sys.columns c ON o.object_id = c.object_id
WHERE
o.name = 'portfolioAttributeCodes'
AND c.name = 'isDisplayed')
BEGIN
UPDATE [cosmos].[portfolioAttributeCodes] SET [isDisplayed] = 1;
END
Now what is happening is it will not create a column (skips the first Id statement and gets into the second one and fails with Invalid column name 'isDisplayed'
Can some one help?
If the table doesn't have the column isDisplayed already the entire batch will fail, as the parser will generate an Invalid column name error. This occurs before any of the SQL is run, so it's not that the second IF is being entered, none of the SQL is run at all. It's effectively a compilation error (like when you try to build you C# application and you have a reference to an object you haven't defined).
You cannot reference a new column in the same scope it was created. You would need to use 2 batches or put the reference to the column in a separate scope, so that its validation is deferred.
A deferred validation would seem fine here:
IF NOT EXISTS (SELECT 1
FROM sys.objects o
INNER JOIN sys.columns c ON o.object_id = c.object_id
WHERE o.name = 'portfolioAttributeCodes'
AND c.name = 'isDisplayed')
BEGIN
ALTER TABLE [cosmos].[portfolioAttributeCodes]
ADD [isDisplayed] bit CONSTRAINT DF_isDisplayed DEFAULT 1 WITH VALUES;
END;
ELSE
BEGIN
EXEC sys.sp_executesql N'UPDATE [cosmos].[portfolioAttributeCodes] SET [isDisplayed] = 1;';
END;
I also switch to an ELSE as there is little point updating the column after you've created it; just create the column with the values in the first place. I name the DEFAULT CONSTRAINT as well as that's just good habit.
Related
Please see the DDL below:
CREATE TABLE Person
(
ID int identity not null,
Name VARCHAR(100),
Age int,
EyeColour varchar(20),
primary key (ID)
)
CREATE INDEX Name ON Person (Name)
CREATE INDEX Age ON Person (Age)
CREATE INDEX EyeColour ON Person (EyeColour)
I can execute the following statement:
ALTER TABLE person
ALTER COLUMN name VARCHAR(110)
However, I cannot execute the following statement:
ALTER TABLE person
ALTER COLUMN name VARCHAR(90)
The error is:
Msg 5074, Level 16, State 1, Line 1
The index 'Name' is dependent on column 'name'.
Msg 4922, Level 16, State 9, Line 1
ALTER TABLE ALTER COLUMN name failed because one or more objects access this column.
Why am I seeing these errors when I reduce the length of a VARCHAR. In what other scenarios would I see this error e.g. change a data type?
Is there an automated way of identifying all the indexes and constraints affected by a data type change and dealing with them?
You could definitely automate the identification part. Here is a script that will find all the indices and foreign keys depending on a table column (I have left finding check constraints as an exercise for the reader). As it is a script, you would have to change the parameters when you run it. You could also turn this into a stored procedure.
However, I don't recommend automating the actions such as dropping indices or constraints. You are better off reviewing the output and deciding if it is really OK to reduce the sizes of the columns or not in the light of what you know about the applications that use these data.
-- parameters
DECLARE
#nm_schema sysname = N'Purchasing',
#nm_table sysname = N'PurchaseOrderHeader',
#nm_column sysname = N'EmployeeID';
DECLARE
#id_table int,
#id_column smallint;
SELECT #id_table = o.object_id
FROM sys.objects o
JOIN sys.schemas s
ON o.schema_id = s.schema_id
WHERE o.name = #nm_table
AND s.name = #nm_schema
AND o.type = 'U';
IF ##ROWCOUNT = 0
BEGIN
RAISERROR(N'Schema %s table %s not found', 0, 1, #nm_schema, #nm_table);
RETURN;
END;
SELECT #id_column = column_id
FROM sys.columns
WHERE object_id = #id_table
AND name = #nm_column;
IF ##ROWCOUNT = 0
BEGIN
RAISERROR(N'Column %s not found in schema %s table %s', 0, 2, #nm_column, #nm_schema, #nm_table);
RETURN;
END;
SELECT 'Index' AS 'dependency', i.name
FROM sys.indexes i
JOIN sys.index_columns ic
ON i.object_id = ic.object_id
AND i.index_id = ic.index_id
WHERE i.object_id = #id_table
AND ic.column_id = #id_column
AND NOT i.type = 0 -- heap
UNION ALL
SELECT 'FKey', f.name
FROM sys.foreign_keys f
JOIN sys.foreign_key_columns fc
ON f.object_id = fc.constraint_object_id
WHERE (f.parent_object_id = #id_table AND fc.parent_column_id = #id_column)
OR (f.referenced_object_id = #id_table AND fc.referenced_column_id = #id_column);
I have inherited a large database project with thousands of views.
Many of the views are invalid. They reference columns that no longer exist. Some of the views are very complex and reference many columns.
Is there an easy way to track down all the incorrect columns references?
This answer finds the underlying columns that were originally defined in the views by looking at sys.views, sys.columns and sys.depends (to get the underlying column if the column has been aliased). It then compares this with the data held in INFORMATION_Schema.VIEW_COLUMN_USAGE which appears to have the current column usage.
SELECT SCHEMA_NAME(v.schema_id) AS SchemaName,
OBJECT_NAME(v.object_id) AS ViewName,
COALESCE(alias.name, C.name) As MissingUnderlyingColumnName
FROM sys.views v
INNER JOIN sys.columns C
ON C.object_id = v.object_id
LEFT JOIN sys.sql_dependencies d
ON d.object_id = v.object_id
LEFT JOIN sys.columns alias
ON d.referenced_major_id = alias.object_id AND c.column_id= alias.column_id
WHERE NOT EXISTS
(
SELECT * FROM Information_Schema.VIEW_COLUMN_USAGE VC
WHERE VIEW_NAME = OBJECT_NAME(v.object_id)
AND VC.COLUMN_NAME = COALESCE(alias.name, C.name)
AND VC.TABLE_SCHEMA = SCHEMA_NAME(v.schema_id)
)
For the following view:
create table test
( column1 varchar(20), column2 varchar(30))
create view vwtest as select column1, column2 as column3 from test
alter table test drop column column1
The query returns:
SchemaName ViewName MissingUnderlyingColumnName
dbo vwtest column1
This was developed with the help of this Answer
UPDATED TO RETRIEVE ERROR DETAILS
So this answer gets you what you want but it isn't the greatest code.
A cursor is used (yes I know :)) to execute a SELECT from each view in a TRY block to find ones that fail. Note I wrap each statement with a SELECT * INTO #temp FROM view X WHERE 1 = 0 this is to stop the EXEC returning any results and the 1=0 is so that SQL Server can optimize the query so that it is in effect a NO-OP.
I then return a list of any views whose sql has failed.
I haven't performed lots of testing on this, but it appears to work. I would like to get rid of the execution of each SELECT from View.
So here it is:
DECLARE curView CURSOR FOR
SELECT v.name AS ViewName
FROM sys.views v
INNER JOIN sys.sql_modules m
on v.object_id = m.object_id
OPEN curView
DECLARE #viewName SYSNAME
DECLARE #failedViews TABLE
(
FailedViewName SYSNAME,
ErrorMessage VARCHAR(MAX)
)
FETCH NEXT FROM curView
INTO #ViewName
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN TRY
exec ('SELECT * INTO #temp FROM ' + #viewName + ' WHERE 1=0' )
END TRY
BEGIN CATCH
INSERT INTO #failedViews VALUES (#viewName, ERROR_MESSAGE())
END CATCH
FETCH NEXT FROM curView
INTO #ViewName
END
CLOSE curView
DEALLOCATE curView
SELECT *
FROM #failedViews
An example of an ERROR returned is:
FailedViewName ErrorMessage
--------------- -------------
vwtest Invalid column name 'column1'.
You could use system tables get information.
SELECT v.VIEW_NAME,v.TABLE_CATALOG,v.TABLE_SCHEMA,v.TABLE_NAME,v.COLUMN_NAME
from INFORMATION_SCHEMA.VIEW_COLUMN_USAGE v
left outer join INFORMATION_SCHEMA.COLUMNS c
ON v.TABLE_CATALOG=c.TABLE_CATALOG AND v.TABLE_SCHEMA=c.TABLE_SCHEMA AND v.TABLE_NAME=c.TABLE_NAME AND v.COLUMN_NAME=c.COLUMN_NAME
WHERE c.TABLE_NAME IS NULL
ORDER BY v.VIEW_NAME
I have a column in my DB which is currently defined as NOT NULL.
I would like to update this column to allow NULLs.
I have the following script to do this however I would like to check first if the column is already NULL (or NOT NULL), as it may have been changed previously.
ALTER TABLE [dbo].[aud]
ALTER COLUMN [actname] nvarchar(50) NULL
Any help appreciated.
Use COLUMNPROPERTY to get column property . You may write something like
SELECT COLUMNPROPERTY(OBJECT_ID('dbo.aud'),'actname','AllowsNull') AS 'AllowsNull';
For more information please visit this link
select is_nullable from sys.columns c inner join sys.tables t on
t.object_id = c.object_id where t.name = 'aud' and c.name = 'actname'
Will give you a BIT representing whether it is nullable or not.
So you could switch on this like
IF EXISTS(SELECT * from sys.columns c inner join sys.tables t on
t.object_id = c.object_id where t.name = 'aud' and c.name = 'actname' AND
is_nullable = 1)
BEGIN
--What to do if nullable
END
ELSE
BEGIN
--What to do if not nullable
END
END
That of course assumes that the table and column exist at all...
There isn't really a need to do that, because if it's already Nullable, changing a column from Nullable to Nullable will have no negative effect.
However you can do it with this query:
SELECT is_nullable
FROM sys.columns
WHERE object_id=object_id('YourTable') AND name = 'yourColumn'
I am using SQL server 2008. I need to find if default value constraint does not exist then create it. Here is what I have tried.
IF (NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_NAME ='MyConstraint'))
BEGIN
ALTER TABLE [XX] ADD CONSTRAINT [MyConstraint] DEFAULT ((-1)) FOR [XXXX]
END
GO
if not exists (
select *
from sys.all_columns c
join sys.tables t on t.object_id = c.object_id
join sys.schemas s on s.schema_id = t.schema_id
join sys.default_constraints d on c.default_object_id = d.object_id
where t.name = 'table'
and c.name = 'column'
and s.name = 'schema')
....
I find this to be easier:
IF OBJECT_ID('SchemaName.MyConstraint', 'D') IS NULL
BEGIN
-- create it here
END
I was a bit puzzled as to why this simple task was so complicated. In my case, I don't have constraint names - only table and column names. I want to check if they already have a default before trying to add one.
After a bit more digging, I came up with this:
IF (SELECT Column_Default FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'MY_TABLE' AND COLUMN_NAME = 'MY_COLUMN') is NULL
BEGIN
ALTER TABLE [dbo].[MY_TABLE]
ADD DEFAULT ('') FOR [MY_COLUMN]
END
GO
I have to implement this in a ginormous boilerplate script, so the shorter the better.
if not exists(select 1 from sys.default_constraints where name = 'SchemaName.MyConstraint')
begin
-- create it here
end
The following works for me on SQL Server 2016.
Assuming I have a table named MY_TABLE and a column MY_COLIUMN.
I would like to add a constrain (default to '-1' ) on MY_COLIUMN that need to add the constrain on.
/* Test for the specific column */
IF EXISTS (select 1 from sys.all_columns c where c.object_id= OBJECT_ID(N'MY_TABLE') and c.name='MY_COLIUMN')
BEGIN
/* Add default if not exits */
IF NOT EXISTS (
select 1 from sys.default_constraints c where c.object_id =
(
select default_object_id from sys.all_columns c where c.object_id = OBJECT_ID(N'MY_TABLE') and c.name='MY_COLIUMN'
)
)
BEGIN
ALTER TABLE MY_TABLE
ADD DEFAULT '-1' FOR MY_COLIUMN;
END
END
GO
I've used the following in the past:
DECLARE #default sysname
SELECT #default = object_name( cdefault ) FROM syscolumns WHERE id = object_id( 'DBO.TABLE' ) AND name = 'COLUMN'
IF ( not #default is null )
BEGIN
...
END
Search the system table where the default costraints of the database are stored, without the schema name:
IF EXISTS(SELECT 1 FROM sys.default_constraints WHERE [name] = 'MyConstraint')
print 'Costraint exists!';
ELSE
print 'Costraint doesn''t exist!';
I know I'm coming to the party late here, but I am a big fan of OBJECTPROPERTY. Here is how to set a default of 1 on a column if the default does not yet exist.
IF (OBJECTPROPERTY(OBJECT_ID('My_constraint_name'),'CnstIsColumn') IS NULL
ALTER TABLE Mytable ADD CONSTRAINT [MY_constraint_name] DEFAULT ((1)) FOR [My_column_name]
Im working on this large DB which has a lot of the business knowledge embedded in the SPs[I know!] and there is a lot of chaining between the SPs. i.e one stored proc calling another.
Im want to find out a list of stored procedures which update a particular column. How would I do that.
Using showplan_All as outlined in
SQL Table and column Parser for stored procedures doesnt work for me, because this is a shared dev db.
using a Sp from master db scanning system text as described is not feasible because I dont have access to the master db.
So how can I find this informaion?
From system view sys.sql_dependencies you can get dependencies at column level.
DECLARE #Schema SYSNAME
DECLARE #Table SYSNAME
DECLARE #Column SYSNAME
SET #Schema = 'dbo'
SET #Table = 'TableName'
SET #Column = 'ColumnName'
SELECT o.name
FROM sys.sql_dependencies AS d
INNER JOIN sys.all_objects AS o ON o.object_id = d.object_id
INNER JOIN sys.all_objects AS ro ON ro.object_id = d.referenced_major_id
INNER JOIN sys.all_columns AS c ON c.object_id = ro.object_id AND c.column_id = d.referenced_minor_id
WHERE (SCHEMA_NAME(ro.schema_id)=#Schema)
and o.type_desc = 'SQL_STORED_PROCEDURE'
and ro.name = #Table
and c.name = #Column
GROUP BY o.name
Have you tried this : EXEC sp_depends #objname = [table name of the column you are interested in].
So for example, if you had a column named Price in a table named Product, you would execute this: EXEC sp_depends #objname = N'Product'.
Simply executing this would give you list of all sps, views, etc which depend on that particular table.
I use this all the time as I work with a db which has over 400 tables :-)
sp_depends page on MSDN
Try something like this:
use YourDatabase;
select [Name]
from sys.procedures
where object_definition([object_id]) like '%YourColumnName%';
Obviously this has the potential to generate a lot of false positives depending on what the column is named but at least you will have a list of procedures to sift through.
Here's one that works in SQL 2000+; Note that as Andrew noted in his, you will get false positives depending on your column name, but it's a starting place:
SELECT DISTINCT o.Name
FROM syscomments c
JOIN sysobjects o ON c.ID = o.ID
WHERE c.Text LIKE '%ColumnName%'
ORDER BY o.Name
use msdb
go
select * from sysjobs j
inner join sysjobsteps s
on j.job_id=s.job_id
where command like '%HBR_INSTRUMENT%'