how to generate a script for the entire database - sql

I've attempted to generate scripts. I've used both of these options:
When attempting to execute the generated script, it works on the initial database creation.
All subsequent attempts to run the generated script result in the following error:
Msg 1781, Level 16, State 1, Line 8739
Column already has a DEFAULT bound to it.
Msg 1750, Level 16, State 0, Line 8739
Could not create constraint or index. See previous errors.
This code seems to work on initial database creation but not on subsequent exections:
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[cfg].[DF__LookupCol__IsPri__46DD686B]') AND type = 'D')
BEGIN
ALTER TABLE [cfg].[LookupColumns] ADD DEFAULT (CONVERT([bit],(0))) FOR [IsPrimaryKey]
END
GO
I've attempted it this as well with the same result:
ALTER TABLE [cfg].[LookupColumns] ADD CONSTRAINT LookupColumnsIsPrimaryKeyConstraint DEFAULT (CONVERT([bit],(0))) FOR [IsPrimaryKey]
What am I doing wrong? What is the meaning of this error? Column already has a DEFAULT bound to it?

This is indeed because you didn't name your constraints, so the second time it attempts to drop the old name then add an additional constraint.
The first time you run the script it checks for a default constraint called DF__LookupCol__IsPri__46DD686B, which of course does not exist.
Then it runs
ALTER TABLE [cfg].[LookupColumns] ADD DEFAULT (CONVERT([bit],(0))) FOR [IsPrimaryKey]
Which creates a new constraint with a new auto-generated name. Next time you run the script, it tries to drop DF__LookupCol__IsPri__46DD686B again, which still doesn't exist, and then tries to add a new constraint, which fails.
So to be able to re-run this script, you should name all your constraints and indexes before generating the scripts.
You can find the system-named default constraints like this:
select name, object_name(object_id) table_name
from sys.default_constraints
where is_system_named = 1
select name, object_name(object_id) table_name
from sys.check_constraints
where is_system_named = 1
select name, object_name(object_id) table_name
from sys.key_constraints
where is_system_named = 1
etc
Or you can look for the __ in the names, but you would want to manually review those of course.

Related

SQL Code Evaluation stopping a valid transaction

As part of the company I am working for at the moment I need to create some database upgrade scripts to replace some work of a previous contractor.
The code before the following block runs, creates the new ID column, and then this script looks to populate the values and then drop some columns.
IF EXISTS (
SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID(N'[Central].[Core.Report].[ReportLessonComp]')
AND name = 'Name')
and
EXISTS (
SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID(N'[Central].[Core.Report].[ReportLessonComp]')
AND name = 'Code')
BEGIN
UPDATE
[Central].[Core.Report].[ReportLessonComp]
SET
CompetencyId = rc.Id
FROM
[Central].[Core.Report].[ReportLessonComp] rlc
INNER JOIN
[Core.Lookup].ReportCompetency rc
ON
rc.Code = rlc.Code and rc.Name = rlc.Name
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN CODE
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN [Name]
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN [Description]
END
GO
When running the if exists \ not exists checks and then select getdate() this works perfeclty fine and gives me the result I expect.
However, when I run the code block above I get error
Msg 207, Level 16, State 1, Line 23
Invalid column name 'Code'.
Msg 207, Level 16, State 1, Line 23
Invalid column name 'Name'.
This script it part of a larger upgrade script and is used in a system calle RoundHouse https://github.com/chucknorris/roundhouse which is the system chosen by the company.
Prior to the above if exists check,
IF (SELECT COUNT(1) FROM sys.columns
WHERE OBJECT_ID = OBJECT_ID('[Central].[Core.Report].[ReportLessonComp]')
AND Name in ('Name','Code')) = 2
which also gave the same issue. I have five tables that I need to update and this is going to stop the team from working if I cant resolve this at my next PR
What can I do in order to stop this from causing the upgrade scripts to fail?
EDIT -- The reason I am linking on varchar fields also is because the previous developer did not create relationships between tables, and was just inserting strings into tables rather than relating by ID causing the potential for unlinked \ inconsistent data.
The table edit prior to this creates the new id column, and this script is getting the value and dropping columns that are no longer needed
SQL Server will parse the whole of the statement prior to execution, so the exists check does not protect you from the update being parsed. If the column has already been dropped, that makes the statement invalid and you get a parse error. The update statement would have to be executed as dynamic SQL, sp_execute basically so that the varchar of the update is not directly parsed.
For SQL Server 2016 and above the drop column can be protected a bit more as well:
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN IF EXISTS CODE

set column to 'not null' in SQL Server

I have a column in a table in a sql server database that I want to set to 'not null'. However, when I execute the query
ALTER TABLE mytable ALTER COLUMN mycolumn INT NOT NULL
I get an
ALTER TABLE ALTER COLUMN mycolumn failed because one or more objects access this column.
How can I find out what kind of object that is and how do I drop it? The database is very simple and is not supposed to make use of foreign keys, triggers etc.
You could search the sys tables to find out what is dependent on the column. This has its limitations, naturally, but by-and-large should give you some indication of what is dependent on your column:
SELECT
OBJECT_NAME(D.Object_ID) AS [Dependent]
,D.Object_ID
FROM sys.sql_dependencies D
INNER JOIN sys.Columns C
ON C.object_id = D.referenced_major_id
AND C.column_id = D.referenced_minor_id
WHERE OBJECT_NAME(C.object_id) = 'MyTable'
AND C.name = 'MyColumn'
;
Once you have the name and object_id of the dependent (it might be a function, a stored procedure, or any number of things) you can go from there.
You might have to drop constraints on the column first,before altering this table.This may be a constraint,index or any thing..below is a small demo showing the same
create table #test
(
id int,
id1 int
)
create index nci_t on #test(id1)
include(id)
alter table #test
alter column id1 varchar(10)
this is the error i got
Msg 5074, Level 16, State 1, Line 2
The index 'nci_t' is dependent on column 'id1'.
Msg 4922, Level 16, State 9, Line 2
ALTER TABLE ALTER COLUMN id1 failed because one or more objects access this column.
also please paste entire error message ,don't strip it

How do I get rid of an orphaned default constraint in T-SQL?

I am trying to create a script in order to create a table in SQL Express 2008 R2, like so:
IF (EXISTS (SELECT * FROM sys.tables WHERE name='Table' AND [type]='U')) BEGIN
DROP TABLE Table
END
GO
CREATE TABLE Table (
col DATETIMEOFFSET CONSTRAINT DF_Table_col DEFAULT GETUTCDATE()
)
GO
I am trying to follow the practice of creating a script that can be re-executed for this release cycle of my project.
But the problem is that I forgot to drop the default constraint DF_Table_col before dropping the table "Table", which I would write as:
IF (EXISTS (SELECT * FROM sys.default_constraints WHERE name='DF_Table_col')) BEGIN
ALTER TABLE Table DROP CONSTRAINT DF_Table_col
END
GO
Now if I try to re-run the script, I get the following error:
Msg 2714, Level 16, State 5, Line 1
There is already an object named 'DF_Table_col' in the database.
Msg 1750, Level 16, State 0, Line 1
Could not create constraint. See previous errors.
How do I get rid of the orphaned constraint DF_Table_col?
I tried to bind this orphan back to a new table by the same name, like so:
exec sp_bindefault 'DF_Table_col', 'Table.col'
but it gives me the following error:
Msg 15050, Level 11, State 1, Procedure sp_bindefault, Line 108
Cannot bind default 'DF_Table_col'. The default must be created using the CREATE DEFAULT statement.
as far as DF_Table_col will be deleted if 'Table' is deleted and it belong to 'Table' there might be 'DF_Table_col'. on an other Table.
If you don't care about the name you can use
CREATE TABLE Table (
col DATETIMEOFFSET DEFAULT GETUTCDATE()
)
GO

Trouble updating new column after adding it

Given the following SQL:
IF EXISTS (SELECT * FROM sys.columns WHERE name = 'NewFieldName' AND object_id = OBJECT_ID('dbo.MyTableName'))
RETURN
-- Add NewFieldName column to part of the Summer 2012 release cycle.
ALTER TABLE dbo.[MyTableName] ADD
[NewFieldName] SmallINT NOT NULL
CONSTRAINT DF_MyTableName_NewFieldName DEFAULT (2)
UPDATE [MyTableName] SET NewFieldName = 1 WHERE [Name] = 'FindMe' --Update one specific value
Produces the following error message:
Msg 207, Level 16, State 1, Line 10 Invalid column name
'NewFieldName'.
I'm sure I'm missing something basic, but trying to put "GO" after the alter makes the UPDATE run everytime and I don't want to do that.
How can I structure this statement so that it will check to see if the column exists and, if it doesn't add it and then set the values as stated in my UPDATE statements?
You need the statement referencing the new column to be compiled after the new column is added. One way of doing this is to run it as a child batch with EXEC.
IF NOT EXISTS (SELECT *
FROM sys.columns
WHERE name = 'NewFieldName'
AND object_id = OBJECT_ID('dbo.MyTableName'))
BEGIN
-- Add NewFieldName column to part of the Summer 2012 release cycle.
ALTER TABLE dbo.[MyTableName]
ADD [NewFieldName] SMALLINT NOT NULL
CONSTRAINT DF_MyTableName_NewFieldName DEFAULT (2)
EXEC(' UPDATE [MyTableName] SET NewFieldName = 1 WHERE [Name] = ''FindMe''')
END
The reason it worked for you originally is presumably because the table itself did not exist when the batch was compiled thus meaning that all statements in it referencing the table are subject to deferred compile.

Writing alter table query inside if statement

I have a table Person which has a column Status. Following code exists in the sqlt file which i am trying to execute
if not exists(select 1 from sysobjects, syscolumns where sysobjects.id = syscolumns.id and sysobjects.name = 'Person' and syscolumns.name = 'Status')
begin
print "Inside the if statement"
end
go
This works fine and nothing is printed as the table and the column both exist.
If i change the file to following
if not exists(select 1 from sysobjects, syscolumns where sysobjects.id = syscolumns.id and sysobjects.name = 'Person' and syscolumns.name = 'Status')
begin
print "Inside the if statement"
alter table Person
add Status char(5) DEFAULT 'INVLD' NOT NULL
end
go
This does not work and i get following error message:
Msg 2705, Level 16, State 3
Server 'NEXUS', Line 6
Column names in each table must be unique. Column name 'Status' in table
'Person' is specified more than once.
Why does it go inside if in this code? What is the solution for this?
I know you are not looking for this answer, but here goes: Don't do that.
Reason is, a structure change is part of a general upgrade. For a given project upgrades happen more than once (like all the time), and usually involve more than one column in more than one table. Therefore, you make (or use) a tool that just modifies your structure and handle that problem separately from the business logic that is making use of a particular column.