SQL Identity(1,1) as a Default constrain - sql

I'm trying to define a new table as follows and I want the IndexPosition column to get the MAX(IndexPosition) + 1 by default.
CREATE TABLE SpeechOutputList
(ID int NOT NULL IDENTITY(1,1),
IndexPosition int DEFAULT (???),
SpeechConfigCode nvarchar(36) NOT NULL,
OutputSentence nvarchar(500),
PRIMARY KEY(ID),
FOREIGN KEY(SpeechConfigCode) REFERENCES SpeechConfig ON UPDATE CASCADE ON DELETE CASCADE);
I want to allow the user to set it's own custom number, but if he hasn't supplied any such number, the default would be the MAX(IndexPosition) + 1.
I thought about DEFAULT IDENTITY(1,1) but it's impossible.
I also thought about: DEFAULT SELECT MAX(IndexPosition) + 1 FROM SpeechOutputList but it's impossible too (Error: 'Subqueries are not allowed in this context. Only scalar expressions are allowed.').
Anyone has an idea?

You can do it using a SEQUENCE object.
SEQUENCE objects are more flexible than the IDENTITY property. They are not bound to one table and you can use the same SEQUENCE object in multiple places if need be. They also give better performance.
Create a SEQUENCE object, specifying the data type (int), the starting value, and how much to increment by.
CREATE SEQUENCE dbo.IndexPositionSequence
AS int
START WITH 1
INCREMENT BY 1;
Then create the table, and use the NEXT VALUE FOR function to get a value from the SEQUENCE object.
CREATE TABLE dbo.SpeechOutputList
(
ID int NOT NULL IDENTITY(1,1),
IndexPosition int DEFAULT (NEXT VALUE FOR IndexPositionSequence),
SpeechConfigCode nvarchar(36) NOT NULL,
OutputSentence nvarchar(500),
PRIMARY KEY(ID)
)
Then we can insert some values into the table. Some of the values have IndexPosition specified and others not.
INSERT INTO dbo.SpeechOutputList (IndexPosition, SpeechConfigCode, OutputSentence)
VALUES
(123, N'abcd', N'The quick brown fox'),
(DEFAULT, N'efgh', N'jumped over the'),
(124, N'ijkl', N'lazy dog'),
(DEFAULT, N'mnop', N'and some cats');
Then display what's in the table.
SELECT *
FROM dbo.SpeechOutputList;
See MSDN > CREATE SEQUENCE (Transact-SQL): https://msdn.microsoft.com/en-us/library/ff878091.aspx

This is my suggestion
CREATE TABLE dbo.DataTable
(
ID int NOT NULL IDENTITY(1,1),
IndexPosition int,
Name varchar(10)
)
go
create trigger dbo.AI_DataTable on dbo.DataTable
after insert
as
begin
declare #id int = (select ID from inserted)
declare #ip int = (select IndexPosition from inserted)
print #id
print #ip
if (#ip is null)
begin
update dbo.DataTable
set IndexPosition = #id + 1
where ID = #id
end
end
-- you can implement any logic in trigger
-- Note: support bulk insert in trigger
insert into dbo.DataTable(Name) values ('First')
insert into dbo.DataTable (Name) values ('Second')
select * from dbo.DataTable
Result:
+----+---------------+--------+
| ID | IndexPosition | Name |
+----+---------------+--------+
| 1 | 2 | First |
| 2 | 3 | Second |
+----+---------------+--------+

I am not at the computer I did this on but I think I have it figured out
I tested this
You can have a Function as a default vaulue
Just have a function that returns the value
Make the function the default value
select isnull(max(IndexPosition),0) + 1 from table;

Related

Having troubles with Identity field of SQL-SERVER

I'm doing a school project about a school theme where I need to create some tables for Students, Classes, Programmes...
I want to add a Group to determined classes with an auto increment in group_id however I wanted the group_id variable to reset if I change any of those attributes(Classes_id,courses_acronym,year_Semesters) how can I reset it every time any of those change??
Here is my table:
CREATE TABLE Classes_Groups(
Classes_id varchar(2),
Group_id INT IDENTITY(1,1),
courses_acronym varchar(4),
year_Semesters varchar(5),
FOREIGN KEY (Classes_id, year_Semesters,courses_acronym) REFERENCES Classes(id,year_Semesters, courses_acronym),
PRIMARY KEY(Classes_id,courses_acronym,year_Semesters,Group_id)
);
Normally, you do not (need to) reset the identity column of a table. An identity column is used to create unique values for every single record in a table.
So you want to generate entries in your groups table based on new entries in your classes table. You might create a trigger on your classes table for that purpose.
Since Group_id is already unique by itself (because of its IDENTITY), you do not need other fields in the primary key at all. Instead, you may create a separate UNIQUE constraint for the combination (Classes_id, courses_acronym, year_Semesters) if you need it.
And if the id field of your classes table is an IDENTITY column too, you could define a primary key in your classes table solely on that id field. And then your foreign key constraint in your new groups table can only include that Classes_id field.)
So much for now. I guess that your database design needs some more additional tuning and tweaking. ;)
where are you setting the values from?, you can have a stored proc and in your query have the columns have an initial value set when stored proc is hit assuming there are values at the beginning
.Then use an IF statement.
declare #initial_Classes_id varchar(2) = --initial value inserted
declare #initial_courses_acronym varchar(4) = --initial value inserted
declare #initial_year_Semesters varchar(5) = --initial value inserted
declare #compare_Classes_id varchar(2) = (select top 1 Classes_id from Classes_Groups order by --PK column desc for last insert); l would add Dateadded and then order with last insert date
declare #compare_courses_acronym varchar(2) = (select top 1 Classes_id from Classes_Groups where Classes_id = #compare_Classes_id);
declare #compare_year_Semesters varchar(2) = (select top 1 Classes_id from Classes_Groups where Classes_id = #compare_Classes_id);
IF (#initial_Classes_id != #compare_Classes_id OR #initial_courses_acronym != #compare_courses_acronym OR #initial_year_Semesters != #compare_year_Semesters)
BEGIN
DBCC CHECKIDENT ('Group_id', RESEED, 1)
Insert into Classes_Groups (courses_acronym,year_Semesters)
values (
courses_acronym,
year_Semesters
)
END
ELSE
BEGIN
Insert into Classes_Groups (courses_acronym,year_Semesters)
values (
courses_acronym,
year_Semesters
)
END
NB: would advice to use int on the primary key. Unless you have a specific purpose of doing so.

Reset INCREMENT VALUE For Identity Column using T-SQL Script

I Need Change Increment Value for Identity Column
For Example
I have create table Test Table with Identity Column
Create Table test
(
Id Int Identity(1,1)
,Name Varchar(200)
)
Now it is easy to Reseed the start value of Identity Column using
DBCC CheckIdent('TEST',Reseed,100)
But I want to change the Increment value 1 to 10
is there any sql command that will work ..
While changing from SSMS 2016 I get this error
To change the increment you need to drop the existing identity() column and add a new column.
alter table test drop column Id;
alter table test add Id int identity(100,10);
If you want to keep existing values, then you will need to create a new table, insert the existing rows with identity_insert on, drop the old table, and rename the new table.
For example:
create table test (id int identity(1,1), name varchar(200) default '')
insert into test default values
insert into test default values
create table new_test (id int identity(100,10), name varchar(200) default '');
set identity_insert new_test on;
insert into new_test (id,name)
select id,name from test
set identity_insert new_test off;
drop table test;
exec sp_rename 'new_test','test';
insert into test default values;
insert into test default values;
select * from test;
rextester demo: http://rextester.com/XDE9355
returns:
+-----+------+
| id | name |
+-----+------+
| 1 | |
| 2 | |
| 100 | |
| 110 | |
+-----+------+

Is it possible to create a stored procedure that, given an arbitrary table, returns a dummy row?

I am wondering whether it's possible to create a procedure like
CREATE PROCEDURE GetDummyRow
#table_name VARCHAR(128)
BEGIN
-- ...
END
that inserts into a table with name #table_name a dummy row and returns it from the procedure. Expect that #table_name has a primary key.
For example, if I have a table like
==========================================
Persons
============================================
id | first_name | last_name | spouse_id
============================================
1 | "John" | "Skeet" | 2
2 | "Jane" | "Skeet" | 1
3 | "Bjarne" | "Stroustrup" | NULL
created with
CREATE TABLE Persons
(
id INT AUTO_INCREMEMENT,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
spouse_id INT,
PRIMARY KEY id,
FOREIGN KEY spouse_id REFERENCES Persons.id
)
and I want
DECLARE #t VARCHAR(128);
#t = 'Persons';
EXEC GetDummyRow(#t)
to return
4 | "ASDbaj" | "OEROANkaskoaASDOLJ" | NULL
or
4 | "okasdALAJajdlaLashdasi" | "OEROANkaskoaASDOLJadasd" | 3
for example.
Is there any logical reason why this would be impossible to make?
This can be simplified a lot if you can use default values to specify the values for the dummy row.
CREATE TABLE Persons
(
id INT IDENTITY(1,1) NOT NULL,
first_name VARCHAR(50) NOT NULL DEFAULT 'Dummy',
last_name VARCHAR(50) NOT NULL DEFAULT 'Value',
spouse_id INT
)
GO
CREATE PROCEDURE GetDummyRow (#table_name NVARCHAR(128))
AS
BEGIN
DECLARE #sql nvarchar(MAX)
SET #sql = N'INSERT INTO ' + #table_name + N' DEFAULT VALUES
SELECT * FROM ' + #table_name + N' WHERE id = SCOPE_IDENTITY()'
exec sp_executesql #sql
END
GO
EXEC GetDummyRow 'Persons'
If the values need to be random, you can use NEWID() as the default:
CREATE TABLE Persons
(
id INT IDENTITY(1,1) NOT NULL,
first_name VARCHAR(50) NOT NULL DEFAULT NEWID(),
last_name VARCHAR(50) NOT NULL DEFAULT NEWID(),
spouse_id INT
)
GO
http://sqlfiddle.com/#!3/85776/1
To answer your question, no there is no reason to think this is impossible to make. As commented it could get complicated...
There are a few requirements that are not quite clear. When you say dummy data you do not say random or unique but I am guessing that you would not want the same dummy data for each row. That would require extra coding based on how many data types you want to support.
I would create a cursor based on the table schema. Then while looping through the columns build in code for the data types and constraints / indexes. Is it a primary or foreign key, is it autonumber or is there a check constraint. You can start small and build in exception handling for table/columns that do not fit the most anticipated types.
Depending on the architecture and complexity of your database you can take advantage of things like autonumbered primary keys.
If there is a foreign key you can either choose a key from the referenced table at random (ie. Top 1 ... From) or call the procedure recursively to insert a dummy record in that table and return the new key. This would require putting most of the functionality in an inner procedure that returns a primary key and a wrapper that returns the result set you are looking for.
I believe these links will be a good start, looking up the topics will lead to other examples.
https://msdn.microsoft.com/en-us/library/ms186778.aspx
https://msdn.microsoft.com/en-us/library/ms177862.aspx

default column value

i'm trying to have a table with a column that has a default value.
right now i can only get this by having a trigger change the value to the default, is it possible to have it declared on the table right from the start?
Would it be possible to have something like the Identity, where i don't have to pass the value into the insert?
egx: insert into Direct values(2)
and the table would become
id | item
1 | 2
the id = 1, would be the deafult value
thanks in advance!
you can create constraints at time of table creation or later.
create table
#test
(
id int identity(1,2),
name char(255) default newid(),
code int default 2
)
---if a table contains all default values,you can insert like below
insert into #test
default values
updated as per comments:
create table
#test1
(
id int identity(1,2),
name char(255) default newid(),
code int default 2,
notdf int
)
---if a table contains one default value and rest all are default
insert into #test1(notdf)
select 2
Further if you want to add a default value after table creation you can do it like below
create table
tt1
(
valuue int,
address char(2) not null
)
insert into tt1
select 1,'a'
ALTER TABLE tt1 ADD CONSTRAINT test1 DEFAULT null FOR address;
Use default. You can change an existing column by doing:
ALTER TABLE t ADD CONSTRAINT df_t_column DEFAULT 1 for id;
An identity is trickier. I would suggest copying the data over to a temporary table, dropping the table, creating it with an identity column and reloading the data.

Finding what value was inserted into an auto-incrementing field

I have two tables:
Rooms:
ID (auto-incrementing primary key, int)
Topic (varchar(50))
MangerId (varchar(50))
Rooms_Users:
UserId (varchar(50))
RoomId (varchar(50))
both fields together are the primary key
I want to insert a room but I also must insert the manger to the table rooms_users.
Here is what I have so far:
ALTER PROCEDURE [dbo].[Creat_Room] #MangerId varchar(50) ,#Topic varchar(50)
AS
BEGIN
SET NOCOUNT
insert into Rooms(ManagerId,Topic) values(#MangerId,#Topic)
insert into Rooms_Users(UserId,RoomId) values(#MangerId,?????????????)
END
The ????????????? is the problem: I don't know what to put here i want to put the roomid i insert above.
You can use the output clause. Look at MSDN here: OUTPUT Clause (Transact-SQL)
Example:
declare #tbl table
(
NewID int
)
insert into Rooms(ManagerId,Topic)
output inserted.ID into #tbl
values(#MangerId,#Topic)
Then the table variable will contains the new id given to the row you inserted
Use the SCOPE_IDENTITY() function:
ALTER PROCEDURE [dbo].[Create_Room]
#ManagerId varchar(50),
#Topic varchar(50)
AS
BEGIN
DECLARE #NewRoomID INT
insert into Rooms(ManagerId, Topic) values(#MangerId, #Topic)
SELECT #NewRoomID = SCOPE_IDENTITY()
insert into Rooms_Users(UserId, RoomId) values(#ManagerId, #NewRoomID)
END
This function will return the last inserted IDENTITY value in this particular scope - the scope of your stored procedure.