I have a table with an auto-generated ID column (and that's all!)
CREATE TABLE [dbo].[EmailGroup](
[EmailGroupGuid] [uniqueidentifier] NOT NULL
CONSTRAINT [PK_EmailGroup] PRIMARY KEY CLUSTERED ([EmailGroupGuid] ASC)
) ON [PRIMARY]
ALTER TABLE [dbo].[EmailGroup]
ADD CONSTRAINT [DF_EmailGroup_EmailGroupGuid] DEFAULT (newsequentialid()) FOR [EmailGroupGuid]
I want to INSERT into this table and extract the generated ID. but, I can't work out if it's possible. It seems to complain about the lack of values/columns.
DECLARE #Id TABLE (Id UNIQUEIDENTIFIER)
INSERT INTO EmailGroup
OUTPUT inserted.EmailGroupID INTO #Id
Is there any way to do this? I mean I could add a dummy column to the table and easily do this:
INSERT INTO EmailGroup (Dummy)
OUTPUT inserted.EmailGroupID INTO #Id
VALUES (1)
however I don't really want to.
I could also specify my own ID and insert that, but again, I don't really want to.
Though I'm not sure why would you need such a table, the answer to your question is to use the keyword DEFAULT:
INSERT INTO EmailGroup (EmailGroupGuid)
OUTPUT inserted.EmailGroupGuid INTO #Id
VALUES(DEFAULT);
Another option is to use DEFAULT VALUES, as shown in Pawan Kumar's answer.
The key difference between these two options is that specifying the columns list and using the keyword default gives you more control.
It doesn't seem much when the table have a single column, but if you will add columns to the table, and want to insert specific values to them, using default values will no longer be a valid option.
From Microsoft Docs on INSERT (Transact-SQL):
DEFAULT
Forces the Database Engine to load the default value defined for a column.
If a default does not exist for the column and the column allows null values, NULL is inserted.
For a column defined with the timestamp data type, the next timestamp value is inserted.
DEFAULT is not valid for an identity column.
DEFAULT VALUES
Forces the new row to contain the default values defined for each column.
So as you can see, default is column based, while default values is row based.
Please use this.
CREATE TABLE [dbo].[EmailGroup]
(
[EmailGroupGuid] [uniqueidentifier] NOT NULL CONSTRAINT [PK_EmailGroup] PRIMARY KEY CLUSTERED ([EmailGroupGuid] ASC)
) ON [PRIMARY]
ALTER TABLE [dbo].[EmailGroup]
ADD CONSTRAINT [DF_EmailGroup_EmailGroupGuid] DEFAULT (newsequentialid()) FOR [EmailGroupGuid]
DECLARE #Id TABLE (Id UNIQUEIDENTIFIER)
INSERT INTO EmailGroup
OUTPUT inserted.EmailGroupGuid INTO #Id DEFAULT VALUES
SELECT * FROM #Id
last 3 OUTPUTs from my Laptop
--92832040-7D52-E811-B049-68F728AE8695
--2B6ADC5F-7D52-E811-B049-68F728AE8695
--0140AF66-7D52-E811-B049-68F728AE8695
Related
I am wondering if there is a way that when creating a table that you can assign a default value to a column if the value is null.
I understand that you can use the syntax DEFAULT however this is only for when the value is absent. Is there a way similar to this that you can say when NULL it will add the default without using a trigger.
CREATE TABLE DBO.TESTS
(
TEST VARCHAR(100) DEFAULT(ISNULL('test',NULL)),
NUM INT
)
This is a test and the kind of thing i was looking at?
UPDATE:
Example input
INSERT INTO TESTS (TEST,NUM)
VALUES (NULL,1)
Where the "NULL" is i would like that to enter the value "test". But also if i was to do the following
INSERT INTO TESTS (NUM)
VALUES (1)
This would also enter the value of "test" into the column "TEST".
I hope this helps.
Yes, there is a way to do what you want. It is called a trigger. You would have to define a trigger that sets the value when a NULL is inserted into the column.
If you use an INSTEAD OF trigger, then you can still declare the column as NOT NULL. The trigger will take care of assigning a value so the constraint is not violated.
So, you can do this. Why you would want to do it is another question. Perhaps you are not familiar with the DEFAULT keyword that allows default values to be inserted using a VALUES() clause. This is explained in the documentation for INSERT.
You can add a default constraint to your table which will automatically add a set value for the column if the insert does not have a value for it:
CREATE TABLE DBO.TESTS
(
TEST VARCHAR(100),
NUM INT
)
ALTER TABLE [DBO].[TESTS] ADD CONSTRAINT [DF_TESTS_TEST] DEFAULT (N'default_value_goes_here') FOR [TEST]
INSERT INTO [DBO].[TESTS] VALUES (NULL, 1)
INSERT INTO [DBO].[TESTS] (num) VALUES (2)
Results
NULL 1
'default_value_goes_here' 2
If you want to check during an insert you can use COALESCE
DECLARE #insertValue VARCHAR(100)
SET #insertValue = NULL
INSERT INTO DBO.TESTS VALUES (COALESCE (#insertValue, 'defaultValue'), 1);
The bottom line is that the column should be non-nullable with a default value.
It's possible to replace null values with default values in a trigger for insert/update, but that doesn't make any sense - first because it means every update/insert will have to do that extra work, and second, because that would make it impossible to insert null to the column (unless the triggers are disabled) so why allow nulls in the first place? It's a mistake that will only be confusing for anyone attempting to use that table.
Think about it from the user side - when you send null to a nullable column, you expect it to be null, you don't expect it to contain a value.
If you run this insert statement:
INSERT INTO TESTS (TEST,NUM)
VALUES (NULL,1)
You expect the table to contain a row where Test is null and num = 1.
You do not expect the Test column to contain the default value.
When providing a value for a column, including NULL, that value will be used. NULL is still a value, just an unknown value. A DEFAULT value will only be used if no value is passed (which, as I just said, NULL is a value so doesn't count).
If you don't want a NULL in your table, then instead stop people supplying them by setting your column as NOT NULL:
CREATE TABLE dbo.TestTable (ID int, String varchar(100) NOT NULL DEFAULT 'test')
GO
--INSERT is successful, String has a value of 'test'
INSERT INTO dbo.TestTable (ID)
VALUES(1);
GO
--INSERT fails, String cannot have a value of NULL
INSERT INTO dbo.TestTable (ID,
String)
VALUES(2,NULL);
GO
SELECT *
FROM dbo.TestTable;
GO
DROP TABLE dbo.TestTable;
GO
A bit of an odd requirement this one.
There is a column on a database (SQL) that is nullable.
I have a constrain in place that populates the column is null/default is provided and it populates from a sequence.
Is it possible to put a constraint in place that ignores any data provided by the insert statement and always puts in the next sequence value?
my current table/constraint is:
CREATE TABLE [dbo].[testmembership](
[id] [int] NOT NULL,
[name] [nvarchar](50) NOT NULL,
[membershipno] [nvarchar](50) NULL
) ON [PRIMARY]
alter table testmembership
add constraint DF_mytblid
default
'PREFIX-'+cast((next value for membershipseq) as nvarchar(50))
for membershipno
If I do the following:
insert into testmembership (id,name,membershipno) values (12,'test',default)
it yeilds the correct sequence generated value.
However, I want it to still have that value from the sequence even if i call this:
insert into testmembership (id,name,membershipno) values (12,'test','ignoreme')
I don't think you can do what you want using a constraint, but you can define a trigger that replaces the normal insert behaviour using the instead of option:
Something like this might work:
create trigger tr on testmembership instead of insert as
insert testmembership (id, name, membershipno)
select id, name, 'PREFIX-' + cast((next value for membershipseq) as nvarchar(50))
from inserted;
I have a table where all columns are auto-populated whenever an insertion happens:
CREATE TABLE …
(
ItemID INT NOT NULL IDENTITY(…),
DateCreated DATETIME2 NOT NULL DEFAULT GETDATE()
);
How do I write a SQL statement that inserts a new row into this table without having to manually provide any concrete values to insert?
(There is already a similar question, but it differs in that it's about a table with some non-DEFAULT columns for which a value must be manually provided.)
Use the DEFAULT VALUES option:
INSERT INTO IdentitySpecification
DEFAULT VALUES;
I need to have one column as the primary key and another to auto increment an order number field. Is this possible?
EDIT: I think I'll just use a composite number as the order number. Thanks anyways.
CREATE TABLE [dbo].[Foo](
[FooId] [int] IDENTITY(1,1) NOT NULL,
[BarId] [int] IDENTITY(1,1) NOT NULL
)
returns
Msg 2744, Level 16, State 2, Line 1
Multiple identity columns specified for table 'Foo'. Only one identity column per table is allowed.
So, no, you can't have two identity columns. You can of course make the primary key not auto increment (identity).
Edit: msdn:CREATE TABLE (Transact-SQL) and CREATE TABLE (SQL Server 2000):
Only one identity column can be created per table.
You can use Sequence for second column with default value IF you use SQL Server 2012
--Create the Test schema
CREATE SCHEMA Test ;
GO
-- Create a sequence
CREATE SEQUENCE Test.SORT_ID_seq
START WITH 1
INCREMENT BY 1 ;
GO
-- Create a table
CREATE TABLE Test.Foo
(PK_ID int IDENTITY (1,1) PRIMARY KEY,
SORT_ID int not null DEFAULT (NEXT VALUE FOR Test.SORT_ID_seq));
GO
INSERT INTO Test.Foo VALUES ( DEFAULT )
INSERT INTO Test.Foo VALUES ( DEFAULT )
INSERT INTO Test.Foo VALUES ( DEFAULT )
SELECT * FROM Test.Foo
-- Cleanup
--DROP TABLE Test.Foo
--DROP SEQUENCE Test.SORT_ID_seq
--DROP SCHEMA Test
http://technet.microsoft.com/en-us/library/ff878058.aspx
Add one identity column and then add a computed column whose formula is the name of the identity column
Now both will increment at the same time
No it is not possible to have more than one identity column.
The Enterprise Manager does not even allow you to set > 1 column as identity. When a second column is made identity
Also note that ##identity returns the last identity value for the open connection which would be meaningless if more than one identity column was possible for a table.
create table #tblStudent
(
ID int primary key identity(1,1),
Number UNIQUEIDENTIFIER DEFAULT NEWID(),
Name nvarchar(50)
)
Two identity column is not possible but if you accept to use a unique identifier column then this code does the same job as well. And also you need an extra column - Name column- for inserting values.
Example usage:
insert into #tblStudent(Name) values('Ali')
select * from #tblStudent
Ps: NewID() function creates a unique value of type uniqueidentifier.
The primary key doesn't need to be an identity column.
You can't have two Identity columns.
You could get something close to what you want with a trigger...
in sql server it's not possible to have more than one column as identity.
I've just created a code that will allow you inserting two identities on the same table. let me share it with you in case it helps:
create trigger UpdateSecondTableIdentity
On TableName For INSERT
as
update TableName
set SecondIdentityColumn = 1000000+##IDENTITY
where ForstId = ##IDENTITY;
Thanks,
A workaround would be to create an INSERT Trigger that increments a counter.
So I have a table that has one identity col : applicationstatusid. its also the primary key.
I want to auto increment another col: applicationnumber
So this is the trigger I write.
create trigger [applicationstatus_insert] on [ApplicationStatus] after insert as
update [Applicationstatus]
set [Applicationstatus].applicationnumber =(applicationstatusid+ 4000000)
from [Applicationstatus]
inner join inserted on [applicationstatus].applicationstatusid = inserted.applicationstatusid
How could I set a constraint on a table so that only one of the records has its isDefault bit field set to 1?
The constraint is not table scope, but one default per set of rows, specified by a FormID.
Use a unique filtered index
On SQL Server 2008 or higher you can simply use a unique filtered index
CREATE UNIQUE INDEX IX_TableName_FormID_isDefault
ON TableName(FormID)
WHERE isDefault = 1
Where the table is
CREATE TABLE TableName(
FormID INT NOT NULL,
isDefault BIT NOT NULL
)
For example if you try to insert many rows with the same FormID and isDefault set to 1 you will have this error:
Cannot insert duplicate key row in object 'dbo.TableName' with unique
index 'IX_TableName_FormID_isDefault'. The duplicate key value is (1).
Source: http://technet.microsoft.com/en-us/library/cc280372.aspx
Here's a modification of Damien_The_Unbeliever's solution that allows one default per FormID.
CREATE VIEW form_defaults
AS
SELECT FormID
FROM whatever
WHERE isDefault = 1
GO
CREATE UNIQUE CLUSTERED INDEX ix_form_defaults on form_defaults (FormID)
GO
But the serious relational folks will tell you this information should just be in another table.
CREATE TABLE form
FormID int NOT NULL PRIMARY KEY
DefaultWhateverID int FOREIGN KEY REFERENCES Whatever(ID)
From a normalization perspective, this would be an inefficient way of storing a single fact.
I would opt to hold this information at a higher level, by storing (in a different table) a foreign key to the identifier of the row which is considered to be the default.
CREATE TABLE [dbo].[Foo](
[Id] [int] NOT NULL,
CONSTRAINT [PK_Foo] PRIMARY KEY CLUSTERED
(
[Id] ASC
) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[DefaultSettings](
[DefaultFoo] [int] NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[DefaultSettings] WITH CHECK ADD CONSTRAINT [FK_DefaultSettings_Foo] FOREIGN KEY([DefaultFoo])
REFERENCES [dbo].[Foo] ([Id])
GO
ALTER TABLE [dbo].[DefaultSettings] CHECK CONSTRAINT [FK_DefaultSettings_Foo]
GO
You could use an insert/update trigger.
Within the trigger after an insert or update, if the count of rows with isDefault = 1 is more than 1, then rollback the transaction.
CREATE VIEW vOnlyOneDefault
AS
SELECT 1 as Lock
FROM <underlying table>
WHERE Default = 1
GO
CREATE UNIQUE CLUSTERED INDEX IX_vOnlyOneDefault on vOnlyOneDefault (Lock)
GO
You'll need to have the right ANSI settings turned on for this.
I don't know about SQLServer.But if it supports Function-Based Indexes like in Oracle, I hope this can be translated, if not, sorry.
You can do an index like this on suposed that default value is 1234, the column is DEFAULT_COLUMN and ID_COLUMN is the primary key:
CREATE
UNIQUE
INDEX only_one_default
ON my_table
( DECODE(DEFAULT_COLUMN, 1234, -1, ID_COLUMN) )
This DDL creates an unique index indexing -1 if the value of DEFAULT_COLUMN is 1234 and ID_COLUMN in any other case. Then, if two columns have DEFAULT_COLUMN value, it raises an exception.
The question implies to me that you have a primary table that has some child records and one of those child records will be the default record. Using address and a separate default table here is an example of how to make that happen using third normal form. Of course I don't know if it's valuable to answer something that is so old but it struck my fancy.
--drop table dev.defaultAddress;
--drop table dev.addresses;
--drop table dev.people;
CREATE TABLE [dev].[people](
[Id] [int] identity primary key,
name char(20)
)
GO
CREATE TABLE [dev].[Addresses](
id int identity primary key,
peopleId int foreign key references dev.people(id),
address varchar(100)
) ON [PRIMARY]
GO
CREATE TABLE [dev].[defaultAddress](
id int identity primary key,
peopleId int foreign key references dev.people(id),
addressesId int foreign key references dev.addresses(id))
go
create unique index defaultAddress on dev.defaultAddress (peopleId)
go
create unique index idx_addr_id_person on dev.addresses(peopleid,id);
go
ALTER TABLE dev.defaultAddress
ADD CONSTRAINT FK_Def_People_Address
FOREIGN KEY(peopleID, addressesID)
REFERENCES dev.Addresses(peopleId, id)
go
insert into dev.people (name)
select 'Bill' union
select 'John' union
select 'Harry'
insert into dev.Addresses (peopleid, address)
select 1, '123 someplace' union
select 1,'work place' union
select 2,'home address' union
select 3,'some address'
insert into dev.defaultaddress (peopleId, addressesid)
select 1,1 union
select 2,3
-- so two home addresses are default now
-- try adding another default address to Bill and you get an error
select * from dev.people
join dev.addresses on people.id = addresses.peopleid
left join dev.defaultAddress on defaultAddress.peopleid = people.id and defaultaddress.addressesid = addresses.id
insert into dev.defaultaddress (peopleId, addressesId)
select 1,2
GO
You could do it through an instead of trigger, or if you want it as a constraint create a constraint that references a function that checks for a row that has the default set to 1
EDIT oops, needs to be <=
Create table mytable(id1 int, defaultX bit not null default(0))
go
create Function dbo.fx_DefaultExists()
returns int as
Begin
Declare #Ret int
Set #ret = 0
Select #ret = count(1) from mytable
Where defaultX = 1
Return #ret
End
GO
Alter table mytable add
CONSTRAINT [CHK_DEFAULT_SET] CHECK
(([dbo].fx_DefaultExists()<=(1)))
GO
Insert into mytable (id1, defaultX) values (1,1)
Insert into mytable (id1, defaultX) values (2,1)
This is a fairly complex process that cannot be handled through a simple constraint.
We do this through a trigger. However before you write the trigger you need to be able to answer several things:
do we want to fail the insert if a default exists, change it to 0 instead of 1 or change the existing default to 0 and leave this one as 1?
what do we want to do if the default record is deleted and other non default records are still there? Do we make one the default, if so how do we determine which one?
You will also need to be very, very careful to make the trigger handle multiple row processing. For instance a client might decide that all of the records of a particular type should be the default. You wouldn't change a million records one at a time, so this trigger needs to be able to handle that. It also needs to handle that without looping or the use of a cursor (you really don't want the type of transaction discussed above to take hours locking up the table the whole time).
You also need a very extensive tesing scenario for this trigger before it goes live. You need to test:
adding a record with no default and it is the first record for that customer
adding a record with a default and it is the first record for that customer
adding a record with no default and it is the not the first record for that customer
adding a record with a default and it is the not the first record for that customer
Updating a record to have the default when no other record has it (assuming you don't require one record to always be set as the deafault)
Updating a record to remove the default
Deleting the record with the deafult
Deleting a record without the default
Performing a mass insert with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record inserts
Performing a mass update with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record updates
Performing a mass delete with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record deletes
#Andy Jones gave an answer above closest to mine, but bearing in mind the Rule of Three, I placed the logic directly in the stored proc that updates this table. This was my simple solution. If I need to update the table from elsewhere, I will move the logic to a trigger. The one default rule applies to each set of records specified by a FormID and a ConfigID:
ALTER proc [dbo].[cpForm_UpdateLinkedReport]
#reportLinkId int,
#defaultYN bit,
#linkName nvarchar(150)
as
if #defaultYN = 1
begin
declare #formId int, #configId int
select #formId = FormID, #configId = ConfigID from csReportLink where ReportLinkID = #reportLinkId
update csReportLink set DefaultYN = 0 where isnull(ConfigID, #configId) = #configId and FormID = #formId
end
update
csReportLink
set
DefaultYN = #defaultYN,
LinkName = #linkName
where
ReportLinkID = #reportLinkId