How to auto increment for a coulmn in sql server limited to partition [duplicate] - sql

Database question here.
Is it possible to make an autoincrement on a secondary or a thirtiary ID?
I need to make something versionbased, so imagine this:
ID Phrase PhraseID PhraseVersion
1 "" 1 1
2 "" 1 2
3 "" 1 3
4 "" 2 1
PhraseID can be the same number, when added to the database.
If the PhraseID exists, i want PhraseVersion to autoincrement in number.
If the PhraseID doesnt exist, i want PhraseVersion to start over, counting from 1.
I this possible?

I would go with a computed column for PhraseVersion, that will take the count of rows with the same PhraseID and Id lower or equal to the current row.
To do that, you need to create a UDF to calculate the PhraseVersion:
CREATE FUNCTION dbo.GetPhraseVersion (
#PhraseId int,
#id int
)
RETURNS INT
AS
BEGIN
RETURN (
SELECT COUNT(*)
FROM T
WHERE PhraseId = #PhraseId
AND Id <= #id
)
END
GO
Then, Create the table with the computed column:
CREATE TABLE T
(
id int identity(1,1),
PhraseId int,
PhraseVersion as dbo.GetPhraseVersion(PhraseId, id)
)
GO
Now for the test - insert 4 records:
INSERT INTO T (PhraseId) VALUES(1),(1),(1),(2)
Select:
SELECT *
FROM T
Results:
id PhraseId PhraseVersion
1 1 1
2 1 2
3 1 3
4 2 1
You can see a live demo on rextester.

This can be accomplished via an insert trigger on the table:
CREATE TABLE Phrases (
ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
PhraseID INT NOT NULL DEFAULT(0),
PhraseVersion INT NOT NULL DEFAULT(0))
GO
-- ==========================================================================================
-- Author: Donna Landy
-- Create Date: 21 Nov 2019
-- Purpose: To populate the PhraseVersion column (subordinate numeric key) on Insert
-- Note: Must cater for >1 row being inserted when this trigger is called
-- Strategy: Construct a temp table with the rows we need to consider, then update one row at a time
-- ==========================================================================================
CREATE TRIGGER Phrases_Insert ON Phrases AFTER INSERT
AS
BEGIN
DECLARE #ID INT
DECLARE #PhraseID INT
DECLARE #PhraseVersion INT
DECLARE #i INT
DECLARE #iMax INT
-- Create and populate temp table
IF OBJECT_ID('tempdb..#phrases', 'U') IS NOT NULL DROP TABLE #phrases
CREATE TABLE #phrases (i INT IDENTITY(1,1) PRIMARY KEY, ID INT, PhraseID INT)
INSERT INTO #phrases (ID, PhraseID) SELECT ID, PhraseID FROM inserted
-- Scan temp table
SET #i=1
SELECT #iMax=MAX(i) FROM #phrases
WHILE #i <= #iMax BEGIN
-- Fetch PhraseID & PhraseVersion for the row we are going to update
SELECT #ID=ID, #PhraseID=PhraseID FROM #phrases WHERE i=#i
-- Find the highest current Ref
SELECT #PhraseVersion=ISNULL(MAX(PhraseVersion),0) FROM Phrases WHERE PhraseID=#PhraseID
-- Update the row
UPDATE Phrases SET PhraseVersion=#PhraseVersion+1 WHERE ID=#ID
-- Increment loop counter
SET #i+=1
END
-- Remove temp table
IF OBJECT_ID('tempdb..#phrases', 'U') IS NOT NULL DROP TABLE #phrases
END
GO

Related

I need to create 3 rows in Student_Fee table when 1 row is inserted in Student table using trigger

Following is the trigger
Create TRIGGER [dbo].[Student]
ON [dbo].[Student]
After INSERT
AS
BEGIN
Insert Into Student_Fee([StudentID],[InstID],[PersonID],[FeeSubmiteTime],[FeeMsg],[Type])
Select NULL,3,PersonID,getdate(),'Student submitted on','Student' from INSERTED
END
I need to create 3 rows in Student_Fee table when 1 row is inserted in Student table.First row in Student_fee must have StudentID Null and for other two rows student ID is filled obtained from previous table. Also, Feemsg should be different for the 3 rows. It is text and could be any value. And for type there are two types Student and Admin and the types are also not fixed. They can vary while inserting rows.
How can I do that by using trigger?
here you go :
CREATE TABLE Temp1abhari (
id INT identity(1, 1)
,number INT
);
CREATE TABLE Temp2abhari (
id INT
,number INT
);
CREATE TRIGGER TTemp1abhari ON Temp1abhari
FOR INSERT
AS
BEGIN
INSERT INTO Temp2abhari
VALUES (
NULL
,1
);
INSERT INTO Temp2abhari
SELECT ID
,2
FROM Inserted;
INSERT INTO Temp2abhari
SELECT ID
,3
FROM Inserted;
END

Alter table to add incrementally primary key records where ID values are null

I have a table in sql server with ID field as the primary key. In the rows of the ID field, some have primary key values while some rows do not have primary key values because the ID column allows null. Now I want to run a query to insert values incrementally into the rows that are null so that they can have primary key values. I have tried using an ALTER command but no head way
because you didn't provide any table structure description and we don't know if there are any business key or some unique combinations of data exists to identify a row without primary key then the easiest way, imho, is to use update cursor:
begin tran
-- rollback
-- commit
select * from [Table_1] where id is null
declare #Id int, #i int = 0
,#MaxId int
set #MaxId = (select Max(Id) from [Table_1] )
declare Update_cur cursor local
for select Id from [Table_1] where id is null
for update of Id
open Update_cur
fetch next from Update_cur into #Id
while ##FETCH_STATUS = 0 begin
set #i += 1
update [Table_1] set Id = #MaxId + #i where CURRENT OF Update_cur
fetch next from Update_cur into #Id
end
close Update_cur
deallocate Update_cur
select * from [Table_1] order by Id
P.S. don't forget to commit or rollback transaction after performing tests
You can DROP that column and ADD again with Auto Increment value.
ALTER TABLE your_table DROP COLUMN ID
ALTER TABLE your_table ADD ID INT IDENTITY(1,1)
This will generate all values from the start and as a result you will lose existing value (upto 6).

SQL Server: How can I create a column with the repeating sequence 1-12?

Long story short, I would like to create a column that repeats the pattern 1,2,3,4,5,6,7,8,9,10,11,12,1,2,3,4,...etc. for (12 * 460343 =) 5524116 rows. Any wisdom on how I could complete this? Thank you!
Insert say 48 then select into from self several times. You will get there real fast. It is surprisingly faster than one would think.
If you create a table with an int autoinc column then at end:
delete from table where id>5524116
Edit here you go
create table idFix
( id bigint auto_increment primary key,
num int not null
)engine=myisam;
-- prime it
insert into idFix(num) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12);
-- this is pretty fast, don't laugh
-- run the following line 19 times
insert into idFix(num) select num from idFix;
-- you now have 6.2m rows (6,291,456)
select count(*) from idFix
delete from idFix where id>5524116;
select count(*) from idFix;
select min(num),max(num) from idFix;
Takes 3 minutes max
Use your helper table then for the love of Pete drop it !
Use a loop and do some mod division with your counter.
DECLARE #LoopCounter bigint
SET #LoopCounter = 0
CREATE TABLE #YourValues
(
YourValue_Key int NOT NULL identity (1,1) PRIMARY KEY,
YourValue_OneThrough12Repating int
)
WHILE #LoopCounter < 5524116
BEGIN
INSERT INTO #YourValues (YourValue_OneThrough12Repating) VALUES ((#LoopCounter % 12) + 1)
SET #LoopCounter = #LoopCounter + 1
END
SELECT * FROM #YourValues
DROP TABLE #YourValues

SQL Server : split column into table in a trigger

I have a table that looks something like this:
UserID Email
-----------------------------------
1 1_0#email.com;1_1#email.com
2 2_0#email.com;2_1#email.com
3 3_0#email.com;3_3#email.com
And I need to create a temp table that will look like this:
UserID Email
-----------------------------------
1 1_0#email.com
1 1_1#email.com
2 2_0#email.com
2 2_1#email.com
3 3_0#email.com
3 3_1#email.com
The temp table will be used in a update trigger and I was wondering if there is a more elegant approach than doing something like this:
-- Create temp table to hold the result table
CREATE TABLE #resultTable(
UserID int,
Email nvarchar(50)
)
-- Create temp table to help iterate through table
CREATE TABLE #tempTable(
ID int IDENTITY(1,1),
UserID int,
Email nvarchar(50)
)
-- Insert data from updated table into temp table
INSERT INTO #tempTable
SELECT [UserId], [Email]
FROM inserted
-- Iterate through temp table
DECLARE #count int = ##ROWCOUNT
DECLARE #index int = 1
WHILE (#index <= #count)
BEGIN
DECLARE #userID int
DECLARE #email nvarchar(50)
-- Get the user ID and email values
SELECT
#userID = [UserID], #email = [Email]
FROM #tempTable
WHERE [ID] = #index
-- Insert the parsed email address into the result table
INSERT INTO #resultTable([UserID], [Email])
SELECT #userID, [Data]
FROM myFunctionThatSplitsAColumnIntoATable(#email, ';')
SET #index = #index + 1
END
-- Do stuff with the result table
You'd better avoid iterative approaches when using T-SQL unless strictly necessary, specially inside triggers.
You can use the APPLY operator.
From MSDN:
The APPLY operator allows you to invoke a table-valued function for each row returned by an outer table expression of a query.
So, you can try to replace all your code with this:
INSERT INTO #resultTable(UserID, Email)
SELECT T1.UserID
,T2.Data
FROM updated T1
CROSS APPLY myFunctionThatSplitsAColumnIntoATable(T1.Email, ';') AS T2

Select data, setting a calculated value into a column

I'm selecting data from a table within a trigger (FOR UPDATE). Some rows I'm selecting have been updated by a transaction, that initiated the trigger, and some rows are not. I'd like to write somewhere in the dataset a flag for every row, which value would be calculated as "id IN (SELECT [id] FROM INSERTED)". This flag would show, is a row updated with the last transaction or not.
Is it possible in SQL?
Sure, I can do 2 separate queries, with 2 different conditions, but the trigger perfomance is real bottleneck...
Here's an example for SQL Server:
if object_id('TriggerTest') is not null
drop table TriggerTest
create table TriggerTest (id int identity, name varchar(50), inLastUpdate bit)
insert TriggerTest (name) values ('joe'), ('barrack'), ('george'), ('dick')
go
create trigger dbo.TriggerTestDelete
on TriggerTest
after update
as begin
declare #date datetime
set #date = GETDATE()
update dbo.TriggerTest
set inLastUpdate =
case when id in (select id from inserted) then 1
else 0
end
end
go
update TriggerTest set name = name where id in (1,2)
update TriggerTest set name = name where id in (1,3)
select * from TriggerTest
This prints:
id name inLastUpdate
1 joe 1
2 barrack 0
3 george 1
4 dick 0