altering DEFAULT constraint on column SQL Server - sql-server

I have an SQL script for creating a table, i would like the default of all but a few columns to be "" the others require a integer default of 0
The following creates the table. Some columns are removed because there are lots
CREATE TABLE [dbo].[PMIPatients]
(
[PID] [varchar](30) NOT NULL,
[PatientFirstName] [varchar](30) NULL,
[PatientLastName] [varchar](30) NULL,
[PatientDOB] [varchar](30) NULL,
[PatientDoctor] [varchar](30) NULL,
[PatientDiet] [varchar](50) NULL,
[PatientFallRiskLevel] [int] NULL,
[BedId] [int] NULL,
[BedDisplayInfo] TEXT NOT NULL DEFAULT ''
CONSTRAINT [PK_HL7Patient] PRIMARY KEY CLUSTERED
([PID] ASC) WITH (PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
)
ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
I wish to set a different default on selected columns, the following code does not work as it says that there is already a default constraint set. So i assumne i have to drop the constraint first.
ALTER TABLE [dbo].[PMIPatients] ADD
DEFAULT ((0))
FOR [PatientFallRiskLevel]
http://www.w3schools.com/sql/sql_default.asp says the follow code should be able to drop the DEFAULT like this
ALTER TABLE Persons
ALTER COLUMN City DROP DEFAULT
but i get a syntax error on DEFAULT
How do i alter/drop the DEFAULT constraint of specific columns

When you add a default, you should use names for your constraints. This way you can later refer to those constraints by name.
ALTER TABLE [dbo].[PMIPatients] ADD CONSTRAINT [PatientFallRiskLevel_Default] DEFAULT ((0)) FOR PatientFallRiskLevel
Then you can drop it using:
ALTER TABLE [dbo].[PMIPatients] DROP CONSTRAINT [PatientFallRiskLevel_Default]

The syntax is:
ALTER TABLE [dbo].[PMIPatients] ADD CONSTRAINT NameYourConstraint DEFAULT ((0)) FOR [PatientFallRiskLevel]
ALTER TABLE [dbo].[PMIPatients] DROP CONSTRAINT NameYourConstraint

When you create a constraint without a name, the SQL Server automatically create internal name. It can be see in the [sys].[default_constraints].
For example:
DROP TABLE IF EXISTS [dbo].[StackOverflow];
CREATE TABLE [dbo].[StackOverflow]
(
[colA] INT
,[colB] INT DEFAULT(0)
,[colC] CHAR(1) DEFAULT('x')
);
GO
SELECT *
FROM [sys].[default_constraints]
WHERE [parent_object_id] = OBJECT_ID('[dbo].[StackOverflow]');
GO
You can use the name to drop the constraint.
If you have more of them, you can use one of the scripts below:
-- all suported editions
DECLARE #DynamicTSQLStataement NVARCHAR(MAX)
,#TableNameWithSchema SYSNAME;
SET #TableNameWithSchema = '[dbo].[StackOverflow]';
SELECT #DynamicTSQLStataement = STUFF
(
(
SELECT ';ALTER TABLE ' + #TableNameWithSchema + ' DROP CONSTRAINT ' + QUOTENAME([name])
FROM [sys].[default_constraints]
WHERE [parent_object_id] = OBJECT_ID('[dbo].[StackOverflow]')
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1
,1
,''
);
EXEC sp_executesql #DynamicTSQLStataement;
GO
or
-- SQL Server 2016 or later
DECLARE #DynamicTSQLStataement NVARCHAR(MAX)
,#TableNameWithSchema SYSNAME;
SET #TableNameWithSchema = '[dbo].[StackOverflow]';
SELECT #DynamicTSQLStataement = STRING_AGG('ALTER TABLE ' + #TableNameWithSchema + ' DROP CONSTRAINT ' + QUOTENAME([name]), ';')
FROM [sys].[default_constraints]
WHERE [parent_object_id] = OBJECT_ID('[dbo].[StackOverflow]');
EXEC sp_executesql #DynamicTSQLStataement;
GO

Related

Make a "normal" table as temporal table

I have a table created like this:
CREATE TABLE address_user
(
[username] VARCHAR(13) NOT NULL,
[address] CHAR(58) NOT NULL,
[id] BIGINT NOT NULL,
CONSTRAINT [PK_ address_user]
PRIMARY KEY CLUSTERED ([id] ASC)
);
Now I want to be able to keep the history modification of this table, so I want to make it as temporal table. I know the script to create a temporal table, the final result should be:
CREATE TABLE address_user
(
[username] VARCHAR(13) NOT NULL,
[address] CHAR(58) NOT NULL,
[id] BIGINT NOT NULL,
[sys_start_time] DATETIME2(7)
GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
[sys_end_time] DATETIME2 (7)
GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
PERIOD FOR SYSTEM_TIME ([sys_start_time], [sys_end_time]),
CONSTRAINT [PK_ address_user]
PRIMARY KEY CLUSTERED ([id] ASC)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE=[dbo].[address_user_history], DATA_CONSISTENCY_CHECK=ON));
The easy way to do that is just delete the previous table, and recreate the table with the good schema.
However, I have a lot of information in my table, save the data and delete the table, recreate it and re-insert the data make me uncomfortable.
So if you have a solution to transform the first table in temporal table without the need to delete everything and recreate it, it should be a great help!
Create the new table address_user_new, insert the data, then use sp_rename to rename address_user to address_user_old and address_user_new to address_user. This can all be done in a transaction to ensure ensure that the transition is atomic and apparently-instantaneous. eg
if object_id('address_user') is not null
ALTER TABLE address_user SET ( SYSTEM_VERSIONING = OFF)
go
if object_id('address_user_new') is not null
ALTER TABLE address_user_new SET ( SYSTEM_VERSIONING = OFF)
go
drop table if exists address_user
drop table if exists address_user_history
drop table if exists address_user_new
drop table if exists address_user_old
go
CREATE TABLE address_user
(
[username] VARCHAR(13) NOT NULL,
[address] CHAR(58) NOT NULL,
[id] BIGINT NOT NULL,
CONSTRAINT [PK_address_user]
PRIMARY KEY CLUSTERED ([id] ASC)
);
go
CREATE TABLE address_user_new
(
[username] VARCHAR(13) NOT NULL,
[address] CHAR(58) NOT NULL,
[id] BIGINT NOT NULL,
[sys_start_time] DATETIME2(7)
GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
[sys_end_time] DATETIME2 (7)
GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
PERIOD FOR SYSTEM_TIME ([sys_start_time], [sys_end_time]),
CONSTRAINT [PK_address_user_new]
PRIMARY KEY CLUSTERED ([id] ASC)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE=[dbo].[address_user_history], DATA_CONSISTENCY_CHECK=ON));
go
set xact_abort on
begin transaction
insert into address_user_new(username,address,id)
select username,address,id
from address_user with (tablockx)
exec sp_rename 'address_user', 'address_user_old', 'OBJECT'
exec sp_rename 'PK_address_user', 'PK_address_user_old', 'OBJECT'
exec sp_rename 'address_user_new', 'address_user', 'OBJECT'
exec sp_rename 'PK_address_user_new', 'PK_address_user', 'OBJECT'
commit transaction

How to alter column from int to Uniqueidentifier in SQL Server 2008

I have a table with column "ID" as datatype int.
CREATE TABLE [dbo].[STUDENT]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[DOB] [datetime] NOT NULL ,
[NAME] [nvarchar](250) NULL,
[CLASS] [nvarchar](50) NULL,
CONSTRAINT [PK_STUDENT_DATA]
PRIMARY KEY CLUSTERED ([ID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 95) ON [PRIMARY]
) ON [PRIMARY]
Now I want to change datatype from int to uniqueidentifier. I have deleted constraint PK_STUDENT_DATA. My ALTER statement is
ALTER TABLE dbo.STUDENT COLUMN ID uniqueidentifier
I am getting error:
Identity column 'HISTORY_ID' must be of data type int, bigint,
smallint, tinyint, or decimal or numeric with a scale of 0, and
constrained to be nonnullable.
The identity column is noncompatible with UniqueIdentifier data type Column.So you need to drop the column and create the new column with UniqueIdentifier data type.Since IDENTITY cannot be used with GUID.Use NEWID instead.
Perform Following Steps:
1. Initially, you need to remove the constraint from table
DROP Index [PK_STUDENT_DATA] ON STUDENT
2. After that
ALTER TABLE STUDENT drop COLUMN ID
3. And finally
ALTER TABLE STUDENT
ADD [Id] UNIQUEIDENTIFIER NOT NULL
PRIMARY KEY NONCLUSTERED DEFAULT NEWID()
Please follow below steps:
Firstly, you should remove PrimaryKey in ID column.
Secondly, you should ALTER ID column with [ID] [int] IDENTITY(1,1) NULL and call update command with NULL value.
Thirdly, call command ALTER TABLE dbo.STUDENT COLUMN ID uniqueidentifier NOT NULL and set primary key to this column.
Case 1: If you want to alter colums without constraint
First you need to drop existing column if you want to change from INT To UNIQUEIDENTIFIER. Do this by following way:
ALTER TABLE TableName
DROP COLUMN COLUMN1, COLUMN2 --IF you want multiple/single column
After that you can add columns by following way:
ALTER TABLE TableName
ADD COLUMN1 UNIQUEIDENTIFIER,
COLUMN2 UNIQUEIDENTIFIER
Case 2: If you want to alter colums which contains constraint
Then firstly remove that constraint and do the above steps.

Why TEXTIMAGE_ON and make table as FileStream

I have a table on an existing SQL Server 2014 database as follows:
CREATE TABLE [dbo].[Files](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Content] [varbinary](max) NULL,
[Created] [datetime2](7) NOT NULL,
[Flag] [nvarchar](100) NULL,
[Key] [uniqueidentifier] NOT NULL,
[MimeType] [nvarchar](400) NOT NULL,
[Name] [nvarchar](400) NULL,
[Pack] [uniqueidentifier] NOT NULL,
[Slug] [nvarchar](400) NULL,
[Updated] [datetime2](7) NOT NULL,
CONSTRAINT [PK_File] PRIMARY KEY CLUSTERED
(
[Id] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
What is TEXTIMAGE_ON and why not just [PRIMARY]?
How can I change this table to use FileStream? So it would have:
[Key] uniqueidentifier rowguidcol not null
constraint DF_File_Key default newid()
constraint UQ_File_Key unique ([Key]),
And
) filestream_on ???
UPDATE
I have the following TSQL:
exec sp_configure filestream_access_level, 2
reconfigure
alter table dbo.Files
set (filestream_on = 'default')
alter table dbo.Files
alter column [Key] add rowguidcol;
alter table dbo.Files
alter column Content filestream;
alter table dbo.Files
add constraint DF__File__Content default (0x),
constraint DF__File__Key default newid(),
constraint UQ__File__Key unique ([Key]);
go
But when I run it I get the error:
Incorrect syntax for definition of the 'TABLE' constraint.
I am using "default" because I want to use the default filegroup.
What am I missing?
From msdn:
SET ( FILESTREAM_ON = { partition_scheme_name | filestream_filegroup_name | "default" | "NULL" } )
Applies to: SQL Server 2008 through SQL Server 2016.
Specifies where FILESTREAM data is stored.
ALTER TABLE with the SET FILESTREAM_ON clause will succeed only if the table has no FILESTREAM columns. The FILESTREAM columns can be added by using a second ALTER TABLE statement.
The TEXTIMAGE_ON is used by default on tables with big columns (nvarchar(max), varbinary(max) etc as mentioned here:
TEXTIMAGE_ON is not allowed if there are no large value columns in the table. TEXTIMAGE_ON cannot be specified if <partition_scheme> is specified. If "default" is specified, or if TEXTIMAGE_ON is not specified at all, the large value columns are stored in the default filegroup. The storage of any large value column data specified in CREATE TABLE cannot be subsequently altered.)

Sql Server: Compare varchar type value in where clause doesn't return results

I have a SQL Server 2012 Web Edition within the AWS RDS database service. The collation is the default one: SQL_Latin1_General_CP1_CI_AS.
In one of the tables I have a column MODIFIED_BY of type varchar(128) - the column collation is default.
The usual values stored into this column are GUIDS with the exception of a few which are hard coded to System. As you can tell it's a table for storing the audit trail transactions where we store the id or System if modification was done as part of the migration.
Anyways - everything above was just the context. Now the weird problem:
I get no records if I run the following, although I should have:
select *
from AUDIT_LOG_TRANSACTIONS alt
where lower(ltrim(rtrim(alt.MODIFIED_BY)))='system'
or
select *
from AUDIT_LOG_TRANSACTIONS alt
where lower(ltrim(rtrim(alt.MODIFIED_BY)))=convert(varchar,'system')
or
select *
from AUDIT_LOG_TRANSACTIONS alt
where lower(ltrim(rtrim(alt.MODIFIED_BY)))=convert(varchar(128),'system')
I get records if I run the following:
select *
from AUDIT_LOG_TRANSACTIONS alt
where alt.MODIFIED_BY like '%System%'
or
select *
from AUDIT_LOG_TRANSACTIONS alt
where lower(ltrim(rtrim(CAST(alt.MODIFIED_BY AS nvarchar(max)))))='system'
UPDATE
Here's the table create script:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[AUDIT_LOG_TRANSACTIONS](
[AUDIT_LOG_TRANSACTION_ID] [int] IDENTITY(1,1) NOT NULL,
[DATABASE] [nvarchar](128) NOT NULL,
[TABLE_NAME] [nvarchar](261) NOT NULL,
[TABLE_SCHEMA] [nvarchar](261) NOT NULL,
[AUDIT_ACTION_ID] [tinyint] NOT NULL,
[HOST_NAME] [varchar](128) NOT NULL,
[APP_NAME] [varchar](128) NOT NULL,
[MODIFIED_BY] [varchar](128) NOT NULL,
[MODIFIED_DATE] [datetime] NOT NULL,
[AFFECTED_ROWS] [int] NOT NULL,
[SYSOBJ_ID] AS (object_id([TABLE_NAME])),
PRIMARY KEY CLUSTERED
(
[AUDIT_LOG_TRANSACTION_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[AUDIT_LOG_TRANSACTIONS] ADD DEFAULT (db_name()) FOR [DATABASE]
GO
ALTER TABLE [dbo].[AUDIT_LOG_TRANSACTIONS] ADD CONSTRAINT [DF_AUDIT_LOG_TRANSACTIONS_MODIFIED_BY] DEFAULT ('System') FOR [MODIFIED_BY]
GO
Could it be there are some "hard to see" characters in your string ?
To eliminate this possibility, I would run a query like this:
select alt.*, LEN(alt.MODIFIED_BY) as 'Length', cast(alt.MODIFIED_BY as varbinary(max)) as 'Bytes' from AUDIT_LOG_TRANSACTIONS alt where alt.MODIFIED_BY like '%System%'
Check that the Length and Bytes columns are what you expect to see.

How to set identity column to created table in SQL server

I created a table in SQL Server like this:
CREATE TABLE [UserName]
(
[ID] [int] NOT NULL ,
[Name] [nvarchar] (50) NOT NULL ,
[Address] [nvarchar] (200) NULL
CONSTRAINT [PK_UserName] PRIMARY KEY CLUSTERED ([ID] ASC)
) ON [PRIMARY]
GO
If I want to make ID an identity column, what do I need? Do I need to drop and create this table and set ID to [ID] [int] IDENTITY(1,1) NOT NULL .
By using drop and create, all of data from UserName table are lost .
Is there another way to set IDENTITY COLUMN to created table's column without losing data?
I use SQL Server 2008 R2 :)
ALTER TABLE [UserName] DROP COLUMN [ID];
ALTER TABLE [UserName]
ADD [ID] integer identity not null;
Try this one -
DECLARE #temp TABLE
(
ID INT NOT NULL
, Name NVARCHAR(50) NOT NULL
, [Address] NVARCHAR(200) NULL
)
INSERT INTO #temp (ID, Name, [Address])
SELECT ID, Name, [Address]
FROM dbo.UserName
DROP TABLE dbo.UserName
CREATE TABLE dbo.UserName
(
[ID] [int] IDENTITY(1,1) NOT NULL
, [Name] [nvarchar] (50) NOT NULL
, [Address] [nvarchar] (200) NULL
CONSTRAINT [PK_UserName] PRIMARY KEY CLUSTERED
([ID] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
SET IDENTITY_INSERT dbo.UserName ON
INSERT INTO dbo.UserName (ID, Name, [Address])
SELECT ID, Name, [Address]
FROM #temp
SET IDENTITY_INSERT dbo.UserName OFF
The easiest way:-
Right click on the table in object explorer and select 'Design'
Select the column for which you want to set identity and go to Column Properties
Under 'Identity Specification' change '(Is Identity)' to 'Yes'
Click Save.... Done :)
Hope This Helps
Here is a solution that is minimally logged.
SELECT
IDENTITY(INT, 1,1) AS ID,
Name, [Address]
INTO dbo.UserName_temp
FROM dbo.UserName;
ALTER TABLE dbo.UserName_temp
ADD CONSTRAINT [PK_UserName] PRIMARY KEY CLUSTERED;
DROP TABLE dbo.UserName;
EXEC sp_rename 'dbo.UserName_temp', 'UserName';
SRC:
http://sqlmag.com/sql-server/appending-identity-column-temporary-table
But the IDENTITY() function can "only in a SELECT statement with an INTO table clause."
http://msdn.microsoft.com/en-us/library/ms189838.aspx

Resources