How to generate AUTOMATIC Number in Teradata SQL - sql

I want to generate AUTOMATIC Number to use TD SQL, for example as follows,
CREATE MULTISET TABLE TEST_TABLE
(
AUTO_NUMBER INT,
NAME VARCHAR(10)
)
PRIMARY INDEX (AUTO_NUMBER);
INSERT INTO TEST_TABLE
VALUES('TOM');
INSERT INTO TEST_TABLE
VALUES('JIM');
INSERT INTO TEST_TABLE
VALUES('JAN');
SELECT * FROM TEST_TABLE;
The result above will be ,
1 TOM
2 JIM
3 JAN

Create a column with the below syntax:
SEQ_NUM decimal(10,0) NOT NULL GENERATED ALWAYS AS IDENTITY
(START WITH 1
INCREMENT BY 1
MINVALUE 1
MAXVALUE 2147483647
NO CYCLE)

Usually there is a column in the table which is unique.
You can use below technique to add a column in your result set if you dont want to add extra column to your table.
select RANK() OVER ( ORDER BY ),T.* SEQ from TABLE T;
It will give you output like:
1 a xx yy
2 b xx yy
3 c xx yy

Related

Adding Random Id for each unique value in table

I have the table like
ID RANDOM_ID
1 123
10 456
25 789
1 1112
55 1314
10 1516
I want the result to be like :
ID RANDOM_ID
1 123
10 456
25 789
1 123
55 1314
10 456
The same ID should have same random_ids. I'm using the update statement to generate the Random_IDs after creating the table.
CREATE TABLE [RANDOMID_TABLE]([ID] [int] NULL, [RANDOM_ID] [int] NULL)
GO
INSERT INTO [RANDOMID_TABLE] ([ID])
select distinct ABC_ID from RANDOMID_ABC
GO
******** This is the update statement for the RANDOM_ID column in
[RANDOMID_TABLE] table ************
UPDATE [RANDOMID_TABLE]
SET RANDOM_ID = abs(checksum(NewId()) % 1000000)
Is there something else that I need to add to the update statement?
Please advise.
Why would you use update for this? Just generate the values when you insert them:
insert into [RANDOMID_TABLE] (ID, RANDOM_ID)
select ABC_ID, abs(checksum(NewId()) % 1000000)
from RANDOMID_ABC
group by ABC_ID;
EDIT:
If your problem is collisions, then fix how you do the assignment. Just assign a number . . . randomly:
insert into [RANDOMID_TABLE] (ID, RANDOM_ID)
select ABC_ID, row_number() over (order by newid())
from RANDOMID_ABC
group by ABC_ID;
This is guaranteed to not return duplicates.
At a total guess, are you simpling wanting to UPDATE the table so that all the values of a specific ID to have the same value for Random_ID? Like this?
CREATE TABLE YourTable (ID int, Random_ID int);
INSERT INTO YourTable
VALUES(1 ,123),
(10,456),
(25,789),
(1 ,1112),
(55,1314),
(10,1516);
GO
WITH CTE AS(
SELECT ID,
Random_ID,
MIN(Random_ID) OVER (PARTITION BY ID) AS Min_Random_ID
FROM YourTable)
UPDATE CTE
SET Random_ID = Min_Random_ID;
GO
SELECT *
FROM YourTable;
GO
DROP TABLE YourTable;
Here is the script you need with use of temporary table (you need it to persist your random results for each unique ID):
DECLARE #Tbl TABLE (ID INT, RANDOM_ID INT)
INSERT #Tbl (Id) VALUES(1), (10), (25), (1), (55), (10)
SELECT Id, abs(checksum(NewId()) % 1000000) AS Random_Id INTO #distinctData FROM #Tbl GROUP BY Id
SELECT D.* FROM #Tbl T JOIN #distinctData D ON D.ID = T.ID
DROP TABLE #distinctData
Obviously, you don't need the first two rows where I create and initialize data table
Result:
Id Random_Id
1 354317
1 62026
10 532304
10 604768
25 874209
55 718643
You want one random value per ID. So one should think that the following would work:
with ids as
(
select distinct id
from randomid_table
)
, ids_with_rnd as
(
select id, abs(checksum(NewId()) % 1000000) as rnd
from ids
)
update randomid_table
set random_id =
(
select rnd
from ids_with_rnd
where ids_with_rnd.id = randomid_table.id
);
It doesn't however. SQL Server is somewhat buggy here and still creates different numbers for the same ID.
So, your best bet may be: do your update that does create different values (your original update statement). Then correct the data as follows:
update randomid_table
set random_id =
(
select min(random_id)
from randomid_table rt2
where rt2.id = randomid_table.id
);
Demo: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=504236db66fba0f12dc7e407a51451f8

Know identity before insert

I want to copy rows from the table within the table itself. But before inserting I need to modify a varchar column appending the value of identity column to it.
My table structure is:
secID docID secName secType secBor
1 5 sec-1 G 9
2 5 sec-2 H 12
3 5 sec-3 G 12
4 7 sec-4 G 12
5 7 sec-5 H 9
If I want to copy data of say docID 5, currently this runs through a loop one row at a time.
I can write my query as
insert into tableA (docID, secName, secType, secBor)
select 8, secName, secType, secBor from tableA where docID = 5
But how can I set value of secName before hand so that it becomes sec-<value of secID column>?
Don't try to guess the value of identity column. In your case you could simply create a computed column secName AS CONCAT('sec-', secID). There is no further need to update that column.
DB Fiddle
It is also possible to create an AFTER INSERT trigger to update the column.
Since SQL Server does not have GENERATED ALWAYS AS ('Sec - ' + id) the only simple option I see is to use a trigger.
Adding to my comment something like:
insert into tableA (docID, secName, secType, secBor)
select
ROW_NUMBER() OVER (ORDER BY DocID),
'Sec -'+ ROW_NUMBER() OVER (ORDER BY DocID),
secType, secBor
from tableA
where docID = 5
In SQL Server 2012 and later, you can achieve this by using the new sequence object.
CREATE SEQUENCE TableAIdentitySeqeunce
START WITH 1
INCREMENT BY 1 ;
GO
create table TableA
(
secId int default (NEXT VALUE FOR TableAIdentitySeqeunce) not null primary key,
varcharCol nvarchar(50)
)
declare #nextId int;
select #nextId = NEXT VALUE FOR TableAIdentitySeqeunce
insert TableA (secId, varcharCol)
values (#nextId, N'Data #' + cast(#nextId as nvarchar(50)))

Insert from select on same table and store old and new identity values in separate table

Temporary table:
declare #Temp_Table table
(
newSID int,
oldSID int
)
Database table: Solutions
Solutions:
* 1 solution1 111
* 2 solution2 111
* 3 solution3 111
After insert,
* 1 solution1 111
* 2 solution2 111
* 3 solution3 111
* 4 solution1 222
* 5 solution2 222
* 6 solution3 222
temp table Expected
oldsID NewSID
* 1 4
* 2 5
* 3 6
This table has SID (identity), SName and cnumber.
Now I want to select some rows from the Solutions table and insert their values into same table.
When inserting each row I want to store the old identity value and new identity value in the temporary table (#Temp_Table).
Please help me with this.
The trick is to use merge instead of a regular insert into..select, since with merge you can use data from both the source and the target in the output clause.
First, create and populate sample table (Please save us this step in your future questions):
CREATE TABLE Solutions
(
SolutionID int identity (1,1),
SolutionName varchar(10),
ClientNumber int
)
INSERT INTO Solutions (SolutionName, ClientNumber) VALUES
('solution1', 111),
('solution2', 111),
('solution3', 111)
Then, declare the mapping table:
DECLARE #Temp_MasterSolutionsTable AS TABLE
(
newSolutionID int,
oldSolutionID int
)
Next, Copy the records you want:
MERGE INTO Solutions USING
(
SELECT SolutionID, SolutionName, ClientNumber
FROM Solutions
--WHERE CONDITION -- I'm guessing you will need a where clause here
) AS s ON 1 = 0 -- Always not matched
WHEN NOT MATCHED THEN
INSERT (SolutionName, ClientNumber)
VALUES (s.SolutionName, s.ClientNumber)
-- and here is where the magic happens
OUTPUT Inserted.SolutionID, s.SolutionID
INTO #Temp_MasterSolutionsTable (newSolutionID, oldSolutionID);
See a live demo on rextester.

Loop through rows and add a number for a column for each of them automatically in SQL Server

I have got an over 500 rows table with a column called ID which is of datetype INT. Currently the values are all NULL.
What I want to achieve is to populate the ID column with an incremental number for each row, say 1, 2, 3, 4, ..., 500 etc.
Please give me a help with any idea how to achieve this by SQL script.
using ROW_NUMBER in a CTE is one way, but here's an alternative; Create a new id1 column as int identity(1,1), then copy over to id, then drop id1:
-- sample table
create table myTable(id int, value varchar(100));
-- populate 10 rows with just the value column
insert into myTable(value)
select top 10 'some data'
from sys.messages;
go
-- now populate id with sequential integers
alter table myTable add id1 int identity(1,1)
go
update myTable set id=id1;
go
alter table myTable drop column id1;
go
select * from myTable
Result:
id value
----------- -------------
1 some data
2 some data
3 some data
4 some data
5 some data
6 some data
7 some data
8 some data
9 some data
10 some data
While you could also drop and recreate ID as an identity, it would lose its ordinal position, hence the temporary id1 column.
#create one temporary table
CREATE TABLE Tmp
(
ID int NOT NULL
IDENTITY(1, 1),
field(s) datatype NULL
)
#suppose your old table name is tbl,now pull
#Id will be auto-increment here
#dont select Id here as it is Null
INSERT INTO Tmp (field(s) )
SELECT
field(s)
FROM tbl
#drop current table
DROP TABLE tbl
#rename temp table to current one
Exec sp_rename 'Tmp', 'tbl'
#drop your temp table
#write alter command to set identitry to Id of current table
good luck

How to increment a second primary key column in a table automatically when a new entry is added for the first primary key column

I am trying to find a way to increment a second primary key column in a table automatically when a new entry is added for the first primary key column. I suppose an example would be best here so here goes.
Suppose I have a table:
CREATE TABLE T
(
SecNum INT NOT NULL,
EntryID INT NOT NULL,
Value FLOAT,
) CONSTRAINT [PK_T] PRIMARY KEY CLUSTERED
(
[SecNum] ASC,
[EntryID] ASC
)
I would run the following statement:
INSERT INTO T (SecNum, Value) VALUES (0, 10)
My table should look like:
SECNUM | ENTRYID | VALUE
-------------------------
0 0 10
I would run the following statement:
INSERT INTO T (SecNum, Value) VALUES (0, 10)
My table should look like:
SECNUM | ENTRYID | VALUE
-------------------------
0 0 10
0 1 10
I would run the following statement:
INSERT INTO T (SecNum, Value) VALUES (1, 20)
My table should look like:
SECNUM | ENTRYID | VALUE
-------------------------
0 0 10
0 1 10
1 0 20
This is possible using an INSTEAD OF trigger:
CREATE TRIGGER TriggerName
ON T
INSTEAD OF INSERT
AS
-- THIS TOP BIT IS OPTIONAL, IT WILL ALLOW ENTRY ID TO BE OVERRIDDEN IF
-- IT IS SUPPLIED TO THE INSERT AND WILL NOT VIOLATE THE PRIMARY KEY
IF NOT EXISTS
( SELECT 1
FROM T
INNER JOIN inserted i
ON i.SecNum = T.secNum
AND i.EntryID = T.EntryID
UNION
SELECT 1
FROM inserted
WHERE EntryID IS NULL
)
BEGIN
INSERT T (SecNum, EntryID, Value)
SELECT SecNum, EntryID, Value
FROM inserted
END
ELSE
-- IF OVERRIDE ABILITY IS NOT REQUIRED JUST USE THE BELOW INSERT
BEGIN
INSERT T (SecNum, EntryID, Value)
SELECT i.SecNum, COALESCE(LastID, 0), i.Value
FROM inserted I
LEFT JOIN
( SELECT SecNum, MAX(T.EntryID) + 1 [LastID]
FROM T
GROUP BY SecNum
) T
ON T.SecNum = i.SecNum
END
Example here
HOWEVER this is not very elegant. It could be worth asking is it really necessary? Could you get away with using a surrogate primary key, and use ROW_NUMBER() to create Entry ID's on the fly?
How about something like this:
INSERT INTO T (SecNum, Value, EntryId)
SELECT 0, 10, count(*)
FROM T WHERE SecNum = 0
It is not the cleanest solution and will perform pretty poorly too. But it should get the job done.
This is how to do it without storing the value in the table (I'm not sure why you want to store it)
TABLE
DECLARE #T TABLE
(
SecNum INT NOT NULL,
EntryID INT,
Value FLOAT
)
DATA
INSERT INTO #T
( SecNum, Value )
VALUES ( 0, 10 )
INSERT INTO #T
( SecNum, Value )
VALUES ( 0, 10 )
INSERT INTO #T
( SecNum, Value )
VALUES ( 1, 20 )
QUERY
SELECT SecNum,
ROW_NUMBER() OVER ( PARTITION BY value ORDER BY Value ) - 1 AS EntryID,
Value
FROM #T
RESULT
SecNum EntryID Value
0 0 10
0 1 10
1 0 20
If the EntryID changes with SecNum AND Value use this query:
SELECT SecNum,
ROW_NUMBER() OVER ( PARTITION BY Value,SecNum ORDER BY Value, SecNum ) - 1 AS EntryID,
Value
FROM #t
RESULT 2
SecNum EntryID Value
0 0 10
0 1 10
1 0 10
1 0 20
Your problem can be solved by using an instead of insert trigger
create trigger Trigger1 on T INSTEAD OF INSERT
as
begin
insert into T(SecNum,EntryID,Value)
select SecNum,
(select count(*) from T where SecNum = i.SecNum) as EntryID,
value
from inserted i
end