I'm developing SQL script, using SSMS, which makes some changes in database:
USE MyDatabase;
BEGIN TRANSACTION;
-- some statements
PRINT(N'#1');
IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = N'dbo' AND TABLE_NAME = N'Table1' AND COLUMN_NAME = 'Table2_Id'))
BEGIN
ALTER TABLE [dbo].[Table1] DROP CONSTRAINT [FK_Table1_Table2_Table2_Id];
ALTER TABLE [dbo].[Table1] DROP COLUMN [Table2_Id];
DROP TABLE [dbo].[Table2];
PRINT(N'Table2 was dropped.');
END
PRINT(N'#2');
IF (NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = N'dbo' AND TABLE_NAME = N'Table2'))
BEGIN
CREATE TABLE [dbo].[Table2]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY,
[Number] INT NOT NULL UNIQUE,
[Name] NVARCHAR(200) NOT NULL,
[RowVersion] TIMESTAMP NOT NULL
);
PRINT(N'Table2 was re-created.');
INSERT INTO [dbo].[Table2]([Number], [Name]) VALUES(-1, N'Default value');
PRINT(N'Default value was inserted in Table2.');
END
-- some statements
COMMIT TRANSACTION;
If Table1 has a column, named Table2_Id, then database has two tables (Table1 and Table2) and a foreign key relationship between them. In that case, I need to:
drop foreign key relationship FK_Table1_Table2_Table2_Id;
drop foreign key column Table1.Table2_Id;
drop Table2;
re-create Table2, using new table schema;
insert some default value in Table2.
When I'm trying to execute this script, I'm getting these errors:
Msg 207, Level 16, State 1, Line 262 Invalid column name 'Number'.
Msg 207, Level 16, State 1, Line 262 Invalid column name 'Name'.
Looks like SQL Server uses old schema for Table2 (which indeed hasn't these columns), but how is this possible, if the table has just created with new schema?
What am I doing wrong?
Server version is SQL Server 2012 (SP1) - 11.0.3128.0 (X64).
UPDATE.
I've added PRINT calls (see script above). There's nothing in message window, except error messages. So, the script isn't being executed... What's going on??
SQL Server tries to compile the whole batch. If the table already exists then it will compile according to the pre-existing definition. The statement referencing the new columns doesn't compile and so the batch never executes.
You need to group the statements using the new definition into a new batch. If you are running this in SSMS just insert a GO
USE MyDatabase;
BEGIN TRANSACTION;
-- some statements
PRINT(N'#1');
IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = N'dbo' AND TABLE_NAME = N'Table1' AND COLUMN_NAME = 'Table2_Id'))
BEGIN
ALTER TABLE [dbo].[Table1] DROP CONSTRAINT [FK_Table1_Table2_Table2_Id];
ALTER TABLE [dbo].[Table1] DROP COLUMN [Table2_Id];
DROP TABLE [dbo].[Table2];
PRINT(N'Table2 was dropped.');
END
GO
PRINT(N'#2');
IF (NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = N'dbo' AND TABLE_NAME = N'Table2'))
BEGIN
CREATE TABLE [dbo].[Table2]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY,
[Number] INT NOT NULL UNIQUE,
[Name] NVARCHAR(200) NOT NULL,
[RowVersion] TIMESTAMP NOT NULL
);
PRINT(N'Table2 was re-created.');
INSERT INTO [dbo].[Table2]([Number], [Name]) VALUES(-1, N'Default value');
PRINT(N'Default value was inserted in Table2.');
END
COMMIT
Otherwise you could run the offending line in a child batch
EXEC(N'INSERT INTO [dbo].[Table2]([Number], [Name]) VALUES(-1, N''Default value'');')
Related
I have one SQLServer in Azure portal and in that server has 2 SQL Databases TestDB1 and TestDB2 is copy of TestDB1. But we used TestDB2 for testing and now it has more data compared to TestDB1. I want to migrate only unavailable data from TestDB2 to TestDB1 as both are having same DB schema. How to do it?
Something like this might work, I've tested it locally and it does merge in test data from a sperate database, full example shown
USE [Playground2] -- Swap for your database name
CREATE TABLE MyTable (
Id BIGINT NOT NULL IDENTITY(1,1) CONSTRAINT PK_MyTable PRIMARY KEY,
[Name] NVARCHAR(50),
[Age] INT,
)
INSERT INTO MyTable([Name], [Age])
VALUES('Andrew', '28'),
('Robert', '38'),
('James', '40'),
('Robin', '40'),
('Peter', '56'), -- second database has this extra data
('Steve', '22') -- second database has this extra data
GO
USE [Playground] -- Swap for your database name
CREATE TABLE MyTable (
Id BIGINT NOT NULL IDENTITY(1,1) CONSTRAINT PK_MyTable PRIMARY KEY,
[Name] NVARCHAR(50),
[Age] INT,
)
INSERT INTO MyTable([Name], [Age])
VALUES('Andrew', '28'),
('Robert', '38'),
('James', '40'),
('Robin', '40')
GO
-- Check that the tables have slightly different data
SELECT * FROM Playground.dbo.MyTable
SELECT * FROM Playground2.dbo.MyTable
BEGIN TRANSACTION
BEGIN TRY
SET IDENTITY_INSERT dbo.MyTable ON
MERGE INTO dbo.MyTable AS TGT
USING [Playground2].dbo.MyTable AS SRC -- Note that we point to the other database here seeing as it is on the same SQL instance
ON TGT.Id = SRC.Id
WHEN MATCHED THEN
UPDATE SET
TGT.[Name] = SRC.[Name],
TGT.[Age] = SRC.[Age]
WHEN NOT MATCHED THEN
INSERT(Id, [Name], [Age])
VALUES(SRC.Id, SRC.[Name], SRC.[Age])
OUTPUT $action AS [Action],
deleted.[Name] AS OldName,
inserted.[Name] AS [NewName],
deleted.[Age] AS OldCountry,
inserted.[Age] AS NewCountry;
SET IDENTITY_INSERT dbo.MyTable OFF
SELECT * FROM dbo.MyTable
ROLLBACK TRANSACTION -- Change to COMMIT TRANSACTION when you are happy with the results
END TRY
BEGIN CATCH
PRINT 'Rolling back changes, there was an error!!'
ROLLBACK TRANSACTION
DECLARE #Msg NVARCHAR(MAX)
SELECT #Msg=ERROR_MESSAGE()
RAISERROR('Error Occured: %s', 20, 101,#msg) WITH LOG
END CATCH
But there also will be tools to do this, but this could be one answer, cheers
I'm getting ready to release a stored procedure that gets info from other tables, does a pre-check, then inserts the good data into a (new) table. I'm not used to working with keys and new tables as much, and my insert into this new table I'm creating is having this error message having to do with the insert/key:
Msg 545, Level 16, State 1, Line 131
Explicit value must be specified for identity column in table 'T_1321_PNAnnotationCommitReport' either when IDENTITY_INSERT is set to ON or when a replication user is inserting into a NOT FOR REPLICATION identity column.
BEGIN
...
BEGIN
IF NOT EXISTS (SELECT * FROM sys.tables where name = N'T_1321_PNAnnotationCommitReport')
BEGIN
CREATE TABLE T_1321_PNAnnotationCommitReport (
[id] [INT] IDENTITY(1,1) PRIMARY KEY NOT NULL, --key
[progressnote_id] [INT] NOT NULL,
[form_id] [INT] NOT NULL,
[question_id] [INT],
[question_value] [VARCHAR](max),
[associatedconcept_id] [INT],
[crte_date] [DATETIME] DEFAULT CURRENT_TIMESTAMP,
[create_date] [DATETIME] --SCHED_RPT_DATE
);
print 'test';
END
END --if not exists main table
SET IDENTITY_INSERT T_1321_PNAnnotationCommitReport ON;
...
INSERT INTO dbo.T_1321_PNAnnotationCommitReport--(progressnote_id,form_id,question_id,question_value,associatedconcept_id,crte_date, create_date) **I tried with and without this commented out part and it's the same.
SELECT progressnote_id,
a.form_id,
question_id,
questionvalue,
fq.concept_id,
getdate(),
a.create_date
FROM (
SELECT form_id,
progressnote_id,
R.Q.value('#id', 'varchar(max)') AS questionid,
R.Q.value('#value', 'varchar(max)') AS questionvalue,
create_date
FROM
#tableNotes t
OUTER APPLY t.form_questions.nodes('/RESULT/QUESTIONS/QUESTION') AS R(Q)
WHERE ISNUMERIC(R.Q.value('#id', 'varchar(max)')) <> 0
) a
INNER JOIN [CKOLTP_DEV]..FORM_QUESTION fq ON
fq.form_id = a.form_id AND
fq.question_id = a.questionid
--select * from T_1321_PNAnnotationCommitReport
SET IDENTITY_INSERT T_1321_PNAnnotationCommitReport OFF;
END
Any ideas?
I looked at some comparable inserts we do at work, insert into select and error message, and insert key auto-incremented, and I think I'm doing what they do. Does anyone else see my mistake? Thanks a lot.
To repeat my comment under the question:
The error is literally telling you the problem. You turn change the IDENTITY_INSERT property to ON for the table T_1321_PNAnnotationCommitReport and then omit the column id in your INSERT. If you have enabled IDENTITY_INSERT you need to supply a value to that IDENTITY, just like the error says.
We can easily replicate this problem with the following batches:
CREATE TABLE dbo.MyTable (ID int IDENTITY(1,1),
SomeValue varchar(20));
GO
SET IDENTITY_INSERT dbo.MyTable ON;
--fails
INSERT INTO dbo.MyTable (SomeValue)
VALUES('abc');
GO
If you want the IDENTITY value to be autogenerated, then leave IDENTITY_INSERT set to OFF and omit the column from the INSERT (like above):
SET IDENTITY_INSERT dbo.MyTable OFF; --Shouldn't be needed normally, but we manually changed it before
--works, as IDENTITY_INSERT IS OFF
INSERT INTO dbo.MyTable (SomeValue)
VALUES('abc');
If you do specifically want to define the value for the IDENTITY, then you need to both set IDENTITY_INSERT to ON and provide a value in the INSERT statement:
SET IDENTITY_INSERT dbo.MyTable ON;
--works
INSERT INTO dbo.MyTable (ID,SomeValue)
VALUES(10,'def');
GO
SELECT *
FROM dbo.MyTable;
IDENTITY_INSERT doesn't mean "Get the RDBMS to 'insert' the value" it means that you want to want to tell the RDBMS what value to INSERT. This is covered in the opening sentence of the documentation SET IDENTITY_INSERT (Transact-SQL):
Allows explicit values to be inserted into the identity column of a table.
(Emphasis mine)
I have tried to drop an existing constraint. Here's what I have:
The name of the constraint is: Data.Leraar.IsGeheim.DefaultValue
and the name of the table is: Data.Leraa.
This is the command I'm currently using:
IF EXISTS(SELECT 1 FROM sys.foreign_keys WHERE parent_object_id = OBJECT_ID(N'dbo.Leraar'))
BEGIN
ALTER TABLE Data.Leraar DROP CONSTRAINT [Data.Leraar.IsGeheim.DefaultValue]
END
If I execute this command, it says Command(s) completed successfully.
But the constraint still exists.
How should I change this command?
So you mean like this:
IF EXISTS(SELECT 1 FROM sys.foreign_keys WHERE parent_object_id = OBJECT_ID(N'dbo.Leraar'))
BEGIN
ALTER TABLE DataData.Leraar DROP FOREIGN KEY IsGeheim.DefaultValue;
END
But then I will get an error
Sorry, but I am using microsoft SQL
if I just do an simple:
ALTER TABLE [Data].[Leraar] DROP CONSTRAINT [Data.Leraar.IsGeheim.DefaultValue]
GO
it works. But I first want to check if it exists
If I do it like this:
IF exists (
SELECT *
FROM sys.default_constraints
WHERE
parent_object_id = OBJECT_ID(N'Data.Leraar') and
name = 'Data.Leraar.IsGeheim.DefaultValue'
)
ALTER TABLE Data.Leraar Drop Constraint Data.Leraar.IsGeheim.DefaultValue
GO
I get error on this line
ALTER TABLE Data.Leraar Drop Constraint Data.Leraar.IsGeheim.DefaultValue
after Data. I get error:
Msg 102, Level 15, State 1, Line 15 Incorrect syntax near '.'.
This works:
IF NOT EXISTS(SELECT 1 FROM sys.foreign_keys WHERE parent_object_id = OBJECT_ID(N'dbo.Leraar'))
BEGIN
ALTER TABLE [Data].[Leraar] ADD CONSTRAINT [Data.Leraar.IsGeheim.DefaultValue] DEFAULT ((1)) FOR [IsGeheim]
END
But to drop if it exists doens work
I have it now like this:
IF EXISTS (
SELECT *
FROM sys.default_constraints
WHERE
parent_object_id = OBJECT_ID(N'Data.Leraar') and
name = 'Data.Leraar.IsGeheim.DefaultValue'
)
ALTER TABLE Data.Leraar Drop Constraint [Data.Leraar.IsGeheim.DefaultValue]
PRINT 'constraint [Data.Leraar.IsGeheim.DefaultValue] has been dropped'
GO
IF NOT EXISTS((SELECT 1 FROM sys.foreign_keys WHERE parent_object_id = OBJECT_ID(N'dbo.Leraar') AND name ='Data.Leraar.IsGeheim.DefaultValue'))
BEGIN
ALTER TABLE [Data].[Leraar] ADD CONSTRAINT [Data.Leraar.IsGeheim.DefaultValue] DEFAULT ((1)) FOR [IsGeheim]
PRINT 'Constraint has been created [Data.Leraar.IsGeheim.DefaultValue]'
END
But is this correct?
You can also query sys.default_constraints system view as follows including the DROP Constraint clause of ALTER TABLE command
Please replace the table name and constraint name according to your case
IF exists (
SELECT *
FROM sys.default_constraints
WHERE
parent_object_id = OBJECT_ID(N'Table_1') and
name = 'DF_Table_1_col1'
)
ALTER TABLE Table_1 Drop Constraint DF_Table_1_col1
GO
I update the above command as follows since as I understand there is a misunderstanding
I assume now the schema for the table Leraar is Data
So please instead of dbo use Data as schema name
IF exists (
SELECT *
FROM sys.default_constraints
WHERE
parent_object_id = OBJECT_ID(N'Data.Leraar') and
name = 'Data.Leraar.IsGeheim.DefaultValue'
)
ALTER TABLE Data.Leraar Drop Constraint [Data.Leraar.IsGeheim.DefaultValue]
GO
You can simply use
IF (OBJECT_ID('Con_First') IS NOT NULL)
BEGIN
ALTER TABLE Customer DROP CONSTRAINT Con_First;
END
Here Con_First is the name of constraint you want to delete.
I have following 5 tables and 1 table is connected as Foreign key in 2 tables. My dilemma is that I cannot figure out which table to drop first. below is the drop table code I am trying and I have created tables in following order
Updated Drop Table Code:
IF EXISTS (SELECT*FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='[Student Major]')
BEGIN
DROP TABLE [Student Major]
END
GO
IF EXISTS (SELECT*FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Major')
BEGIN
DROP TABLE Major
END
GO
IF EXISTS (SELECT*FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Citizenship')
BEGIN
DROP TABLE Citizenship
END
GO
IF EXISTS (SELECT*FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Country')
BEGIN
DROP TABLE Country
END
IF EXISTS (SELECT*FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Student')
BEGIN
DROP TABLE Student
END
GO
CREATE TABLE Student(
[Student ID] INT IDENTITY PRIMARY KEY
,[First Name] varchar (50) NOT NULL
,[Last Name] varchar (30) NOT NULL
)
GO
CREATE TABLE Country(
[Country ID] int identity PRIMARY KEY NOT NULL
,[Country of Birth] varchar (10)
,[Student ID] int FOREIGN KEY REFERENCES Student([Student ID]) NOT NULL
)
GO
CREATE TABLE Citizenship(
[Citizenship ID] int identity PRIMARY KEY
,[Country of Citizenship1] varchar (10)
,[Country of Citizenship2] varchar (10)
,[Student ID] int FOREIGN KEY REFERENCES Student([Student ID]) NOT NULL
,[Country ID] int FOREIGN KEY REFERENCES Country([Country ID]) NOT NULL
)
GO
CREATE TABLE Major(
[Major ID] int identity PRIMARY KEY
,[Major Name] varchar(30) NOT NULL
)
GO
CREATE TABLE [Student Major](
[Student MajorID] int identity
,[Student ID] int FOREIGN KEY REFERENCES Student([Student ID])
,[Major ID] int FOREIGN KEY REFERENCES Major([Major ID])
,[Graduated Major] varchar (30) NOT NULL
)
GO
I Would like to drop table in correct order
Errors:
Could not drop object 'Student' because it is referenced by a FOREIGN KEY constraint.
Also,Please provide explanation of dropping the table. I am new to SQL.
Thanks in advance!
Here is the way that I usually do it:
SELECT 'ALTER TABLE [' + O.[name] + '] DROP ' + F.[name]
FROM sys.objects O
INNER JOIN sys.foreign_keys F ON (F.parent_object_id = O.object_id)
WHERE O.[type] = 'U'
SELECT 'DROP TABLE [' + [name] + ']'
FROM sys.objects
WHERE [type] = 'U'
ORDER BY create_date DESC
This will generate a record set such as
ALTER TABLE Foo DROP FK_BLAH
ALTER TABLE Bar DROP FK_BAH
...
DROP TABLE Foo
DROP TABLE Bar
Which, you can then just copy and paste into a query window, and run from there.
(At the time that I'm writing this answer, I don't have access to an instance of SQL server, but I use code like the above all the time.)
DROP TABLE Student_Major; GO
SELECT 1 FROM Citizenship; GO
DROP TABLE Citizenship; GO
SELECT 1 FROM Major; GO
DROP TABLE Major; GO
SELECT 1 FROM Country; GO
DROP TABLE Country; GO
SELECT 1 FROM Student; GO
DROP TABLE Student; GO
It's just like you said, it has to be in the order so that any table that is referenced by a FK is not dropped, as long as the FK is there.
EDIT: GO forces the end of the batch
EDIT: I notice you have the GO in there already. You could use Information_schema to find the constraints associated with the table and drop them first, but I feel like you shouldn't need to do that. What if you injected a dummy query imbetween each DROP statement. It's hacky but if you don't feel like having to understand all the information_schema stuff it might be easier if it works.
You could first remove all FK constraints by:
ALTER TABLE ... DROP CONSTRAINT ...;
Then drop tables in any order.
If you are using SQL Server 2016 and above you could use DIE(drop if exists) and multiple tables at-once (still order matters):
DROP TABLE IF EXISTS [Student Major], Major, Citizenship, Country,Student;
DBFiddle Demo
If you are in doubt, and don't want to remove your constraints for some reason, you can always drop your tables in the exact opposite order in which you created them.
Since the first table doesn't reference any other, but maybe is referenced by other tables created after it, you should delete it last.
For the remaining tables, apply same logic. The first of the remaining tables is to be deleted last among them, and so on.
Its about ORACLE (PL/SQL) script. I am not very familiar with databse to be honest.
I want to alter the length of a string in a column from 30 to 60. It is not null column.
If the table is empty and I run following script then it works:
alter table [TABLE_NAME] add ( NEW_COLUMN NVARCHAR2(60) DEFAULT 'null' NOT NULL );
/
alter table [TABLE_NAME] DROP CONSTRAINT PK_[TABLE_NAME];
/
begin
for rec in ( select * from [TABLE_NAME] )
loop
update [TABLE_NAME] set NEW_COLUMN =rec.OLD_COLUMN where Name_ID=rec.Name_ID;
end loop;
end;
/
alter table [TABLE_NAME] drop column OLD_COLUMN;
/
alter table [TABLE_NAME] rename column NEW_COLUMN to OLD_COLUMN;
/
alter table [TABLE_NAME] add CONSTRAINT PK_[TABLE_NAME] PRIMARY KEY(Name_ID);
/
But if the table has values then this script does not work.
It gives error: Cannot drop constraint - nonexistent constraint
However, if I remove lines about constraints (second and second last) then it works.
Now I don’t know if the table will be empty or it will have data so I need a script that can work in both the situations. Can anyone help please?
Following script for creating table:
CREATE TABLE TABLE_NAME
(
Name_ID NVARCHAR2(7) NOT NULL,
OLD_COLUMN NVARCHAR2(30) NOT NULL,
CONSTRAINT PK_TABLE_NAME PRIMARY KEY(Name_ID, OLD_COLUMN)
)
/
So while creating table it puts the primary key constraints but while updating table it drops this constraints somehow. I am simplyfying the sitation here. The tables are updates through java code. What I need to do is make a script that work in both situations - with data or just after creating table and modifying the column.
The following script works for me, regardless of whether the insert statement is present or not (ie. the table has or has not data):
CREATE TABLE TABLE_NAME
(
Name_ID NVARCHAR2(7) NOT NULL,
OLD_COLUMN NVARCHAR2(30) NOT NULL,
CONSTRAINT PK_TABLE_NAME PRIMARY KEY(Name_ID, OLD_COLUMN)
);
insert into table_name (name_id, old_column)
values ('test', 'test_old_col');
commit;
alter table table_name add (new_column nvarchar2(60) default 'null' not null);
update table_name set new_column = old_column;
commit;
alter table table_name drop constraint PK_TABLE_NAME;
alter table table_name drop column old_column;
alter table table_name rename column new_column to old_column;
alter table TABLE_NAME add CONSTRAINT PK_TABLE_NAME PRIMARY KEY(Name_ID, old_column);
drop table table_name;
I have assumed that you meant to recreate the primary key with the old_column in it, otherwise you would be unable to recreate it if there are any duplicate values present in the name_id column.
As an alternative, you can save the old data and create a new table with new parameters. Then insert the old values.
In SQL Server Management Studio:
"your database" => task => generatescripts => select specific database object => "your table" => advanced => types of data to script - schema and data => generate