Let's say I have the following table:
id name age
John 23
Mary 22
Mike 25
etc etc
I would like to generate consecutive number into id column for every record. Could anyone help me?
Sorry if I asked the same question as asked before.
You can use ROW_NUMBER() to add a sequential number:
SELECT
id = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)),
name,
age
FROM yourTable
Here is an example of how to update table through CTE:
DECLARE #t TABLE ( ID INT, Name NVARCHAR(50) )
INSERT INTO #t
VALUES ( 3, 'a' ),
( 5, 'b' ),
( 10, 'c' )
SELECT * FROM #t;
WITH cte
AS ( SELECT ID ,
ROW_NUMBER() OVER ( ORDER BY ( SELECT 1 ) ) AS RN
FROM #t
)
UPDATE cte
SET ID = RN
SELECT * FROM #t
Output:
ID Name
3 a
5 b
10 c
ID Name
1 a
2 b
3 c
Instead of
ROW_NUMBER() OVER ( ORDER BY ( SELECT 1 ) ) AS RN
you can do
ROW_NUMBER() OVER ( ORDER BY Name ) AS RN
in order to increment values by ordering in Name column.
Alter your table then add identity and it will generate value
ALTER TABLE dbo.YourTable
Add id Int Identity(1, 1)
Related
Given the following table structure
Column
Id
Name
DateCreated
with the following data
id
Name
DateCreated
1
Joe
1/13/2021
2
Fred
1/13/2021
3
Bob
1/12/2021
4
Sue
1/12/2021
5
Sally
1/10/2021
6
Alex
1/9/2021
I need SQL that will page over the data based on datecreated. The query should return the top 3 records, and any record which also shares the datecreated of the top 3.
So give the data above, we should get back Joe, Fred and Bob (as the top 3 records) plus Sue since sue has the same date as Bob.
Is there something like ROW_NUMBER that increments for each row where it encounters a different value.
For some context this query is being used to generate an agenda type view, and once we select any date we want to keep all data for that date together.
EDIT
I do have a solution but it smells:
;WITH CTE AS ( SELECT ROW_NUMBER() OVER(ORDER BY DateCreated DESC) RowNum,CAST(DateCreated AS DATE) DateCreated,Name
FROM MyTable),
PAGE AS (SELECT *
FROM CTE
WHERE RowNum<=5)
SELECT *
FROM Page
UNION
SELECT *
FROM CTE
WHERE DateCreated=(SELECT MIN(DateCreated) FROM Page)
I've used a TOP 3 WITH TIES example and a ROW_NUMBER example and a CTE to return four records:
DROP TABLE IF EXISTS #tmp
GO
CREATE TABLE #tmp (
Id INT PRIMARY KEY,
name VARCHAR(20) NOT NULL,
dateCreated DATE
)
GO
INSERT INTO #tmp VALUES
( 1, 'Joe', '13 Jan 2021' ),
( 2, 'Fred', '13 Jan 2021' ),
( 3, 'Bob', '12 Jan 2021' ),
( 4, 'Sue', '12 Jan 2021' ),
( 5, 'Sally', '10 Jan 2021' ),
( 6, 'Alex', '9 Jan 2021' )
GO
-- Gets same result
SELECT TOP 3 WITH TIES *
FROM #tmp t
ORDER BY dateCreated DESC
;WITH cte AS (
SELECT ROW_NUMBER() OVER( ORDER BY dateCreated DESC ) rn, *
FROM #tmp
)
SELECT *
FROM #tmp t
WHERE EXISTS
(
SELECT *
FROM cte c
WHERE rn <=3
AND t.dateCreated = c.dateCreated
)
My results:
As #Charlieface, we only need to replace ROW_NUMBER with DENSE_RANK. So that the ROW_NUMBER will be tied according to the same value.
When we run the query:
SELECT DENSE_RANK () OVER(ORDER BY DateCreated DESC) RowNum,CAST(DateCreated AS DATE) DateCreated,Name
FROM MyTable
The result will show as follows:
So as a result, we can set RowNum<=3 in the query to get the top 3:
;WITH CTE AS ( SELECT DENSE_RANK() OVER(ORDER BY DateCreated DESC) RowNum,CAST(DateCreated AS DATE) DateCreated,Name
FROM MyTable),
PAGE AS (SELECT *
FROM CTE
WHERE RowNum<=3)
SELECT *
FROM Page
UNION
SELECT *
FROM CTE
WHERE DateCreated=(SELECT MIN(DateCreated) FROM Page)
The First one is as yours the second one is as above. The results of the two queries are the same.
Kindly let us know if you need more infomation.
I have this:
SELECT NEWID() as id,
'OwnerReassign' as name,
1 as TypeId,
'MyOrganisation' as OrgName,
'07DA8E53-74BD-459C-AF94-A037897A51E3' as SystemUserId,
0 as StatusId,
GETDATE() as CreatedAt,
'{"EntityName":"account","Ids":["'+CAST(AccountId as varchar(50))+'"],"OwnerId":"0C01C994-1205-E511-988E-26EE4189191B"}' as [Parameters]
FROM Account
WHERE OwnerIdName IN ('John Smith') AND New_AccountType = 1
Within the parameter field is an id (0C01C994-1205-E511-988E-26EE4189191B). Is it possible it could sequentially assign a different id from a list for each row? There are 5 id's in total.
What i'm trying to get to is this result set equally split between the 5 different id's.
Thanks
You can add one more NEWID() in the sub query and handle in the SELECT as below:
SELECT id, [name], TypeId, OrgName, SystemUserId, StatusId, CreatedAt,
'{"EntityName":"account","Ids":["' + AccountId +'"],"OwnerId":"' + ParamId + '"}' as [Parameters]
FROM (
SELECT NEWID() as id,
'OwnerReassign' as name,
1 as TypeId,
'MyOrganisation' as OrgName,
'07DA8E53-74BD-459C-AF94-A037897A51E3' as SystemUserId,
0 as StatusId,
GETDATE() as CreatedAt,
CAST(NEWID() AS VARCHAR (36)) as ParamId,
CAST(AccountId as varchar(50)) as AccountId
FROM Account
WHERE OwnerIdName IN ('John Smith') AND New_AccountType = 1
) A
You can use something like the following. Basically, use a row number for both your IDs and your data table to update, then do a MOD (%) operation with the amount of ID's you want to assign, so your data table to update is split into N groups. Then use that group ID to assign each ID.
IF OBJECT_ID('tempdb..#IDsToAssign') IS NOT NULL
DROP TABLE #IDsToAssign
CREATE TABLE #IDsToAssign (
IDToAssign VARCHAR(100))
-- 3 IDs example
INSERT INTO #IDsToAssign (
IDToAssign)
SELECT IDToAssign = NEWID()
UNION ALL
SELECT IDToAssign = NEWID()
UNION ALL
SELECT IDToAssign = NEWID()
DECLARE #AmountIDsToAssign INT = (SELECT COUNT(1) FROM #IDsToAssign)
IF OBJECT_ID('tempdb..#Account') IS NOT NULL
DROP TABLE #Account
CREATE TABLE #Account (
PrimaryKey INT PRIMARY KEY,
AssignedID VARCHAR(100))
-- 10 Rows example
INSERT INTO #Account (
PrimaryKey)
VALUES
(100),
(200),
(351),
(154),
(194),
(345),
(788),
(127),
(124),
(14)
;WITH DataRowNumber AS
(
SELECT
A.*,
RowNumber = ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM
#Account AS A
),
IDsRowNumbers AS
(
SELECT
D.IDToAssign,
RowNumber = ROW_NUMBER() OVER (ORDER BY D.IDToAssign)
FROM
#IDsToAssign AS D
),
NewIDAssignation AS
(
SELECT
R.*,
IDRowNumberAssignation = (R.RowNumber % #AmountIDsToAssign) + 1
FROM
DataRowNumber AS R
)
UPDATE A SET
AssignedID = R.IDToAssign
FROM
NewIDAssignation AS N
INNER JOIN IDsRowNumbers AS R ON N.IDRowNumberAssignation = R.RowNumber
INNER JOIN #Account AS A ON N.PrimaryKey = A.PrimaryKey
SELECT
*
FROM
#Account AS A
ORDER BY
A.AssignedID
/* Results:
PrimaryKey AssignedID
----------- ------------------------------------
124 1CC7F0F1-7EDE-4F7F-B0A3-739D74A62390
194 1CC7F0F1-7EDE-4F7F-B0A3-739D74A62390
351 1CC7F0F1-7EDE-4F7F-B0A3-739D74A62390
788 2A58A573-EDCB-428E-A87A-6BFCED265A9C
200 2A58A573-EDCB-428E-A87A-6BFCED265A9C
127 2A58A573-EDCB-428E-A87A-6BFCED265A9C
14 2A58A573-EDCB-428E-A87A-6BFCED265A9C
100 FD8036DA-0E15-453E-8A59-FA3C2BDB8FB1
154 FD8036DA-0E15-453E-8A59-FA3C2BDB8FB1
345 FD8036DA-0E15-453E-8A59-FA3C2BDB8FB1
*/
The ordering of the ROW_NUMBER() function will determine how ID's are assigned.
You could potentially do this by using the ROW_NUMBER() field in a subquery; for example:
SELECT NEWID() as id, 'OwnerReassign' as name, 1 as TypeId,
'MyOrganisation' as OrgName,
'07DA8E53-74BD-459C-AF94-A037897A51E3' as SystemUserId,
0 as StatusId, GETDATE() as CreatedAt,
case B / ##ROWCOUNT
when 0 then '0C01C994-1205-E511-988E-26EE4189191B'
when 1 then '12345677-1205-E511-988E-26EE4189191B'
when 2 then '66666666-1205-E511-988E-26EE4189191B'
etc...
end
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY A.Id)
FROM Account A
WHERE OwnerIdName IN ('John Smith') AND New_AccountType = 1
) AS B
If you want the system to pick those values then you could put then in their own temporary table, too.
I have a table like this :
Table1:
[Id] [TDate] [Score]
1 1.1.00 50
1 1.1.00 60
2 1.1.01 50
2 1.1.01 70
2 1.3.01 40
3 1.1.00 80
3 1.1.00 30
3 1.2.00 40
My desired output should be like this:
[ID] [TDate] [Score]
1 1.1.00 60
2 1.1.01 70
2 1.3.01 40
3 1.1.00 80
3 1.2.00 40
So fare, I have written this:
SELECT DISTINCT TOP 2 Id, TDate, Score
FROM
( SELECT Id, TDate, Score, ROW_NUMBER() over(partition by TDate order by Score) Od
FROM Table1
) A
WHERE A.Od = 1
ORDER BY Score
But it gives me :
[ID] [TDate] [Score]
2 1.1.01 70
3 1.1.00 80
of course I can do this:
"select top 2 ...where ID = 1"
and then:
union
`"Select top 2 ... where ID = 2"`
etc..
but I have a 100,000 of this..
Any way to generalize it to any Id?
Thank you.
WITH TOPTWO AS (
SELECT Id, TDate, Score, ROW_NUMBER()
over (
PARTITION BY TDate
order by SCORE
) AS RowNo
FROM [table_name]
)
SELECT * FROM TOPTWO WHERE RowNo <= 2
Your output doesn't make sense. Let me assume you want two rows per id. Then the query would look like:
SELECT TOP 2 Id, TDate, Score
FROM (SELECT Id, TDate, Score,
ROW_NUMBER() over (partition by id order by Score DESC) as seqnum
FROM Table1
) t
WHERE seqnum <= 2
ORDER BY Score;
Notes:
This assumes that you want two rows per id. Hence, id is in the PARTITION BY.
The WHERE now selects two rows per group in the PARTITION BY.
There is no need for SELECT DISTINCT in the outer query -- at least for this question.
Try this : Make partition by ID and TDate and sort by score in descending order
ROW_NUMBER() over(partition by ID,TDate order by Score DESC) Od
Complete script
WITH CTE AS(
SELECT *,
ROW_NUMBER() over(partition by ID,TDate order by Score DESC) RN
FROM TableName
)
SELECT *
FROM CTE
WHERE RN = 1
Unless I am missing something this can be done with a simple group by
First I prepare a temp table for testing :
declare #table table (ID int, TDate varchar(10), Score int)
insert into #Table values(1, '1.1.00', 50)
insert into #Table values(1, '1.1.00', 60)
insert into #Table values(2, '1.1.01', 50)
insert into #Table values(2, '1.1.01', 70)
insert into #Table values(2, '1.3.01', 40)
insert into #Table values(3, '1.1.00', 80)
insert into #Table values(3, '1.1.00', 30)
insert into #Table values(3, '1.2.00', 40)
Now lets do a select on this table
select ID, TDate, max(Score) as Score
from #table
group by ID, TDate
order by ID, TDate
The result is this :
ID TDate Score
1 1.1.00 60
2 1.1.01 70
2 1.3.01 40
3 1.1.00 80
3 1.2.00 40
So all you need to do is change #table to your table name and you are done
I am trying to select and inset X rows into a temp table at each execution, I have numbered the rows. However, I tried using PERCENT and TOP but not getting the desire results.
Note: I am not trying to get specific number of rows between certain numbers. I just need to get a fix number, and if the number of available rows is below the select request, then get less but do not exceed.
I assigned the row numbers like this:
WITH GetRecordByIncrement AS
(
SELECT
[RowNumber] = ROW_NUMBER() OVER (ORDER BY UserID ASC)
,[Column1]
,[Column2]
,[Column3]
FROM MySchema.MyTable
)
How would I get, example: 100 or less rows? This does not work using the row number.
Something like this would work:
DECLARE #table TABLE ( c1 INT, c2 INT, c3 INT );
;
WITH MyRows
AS ( SELECT TOP 100
ROW_NUMBER() OVER ( ORDER BY message_id ) AS RowNum ,
message_id ,
severity
FROM sys.messages
)
INSERT INTO #Table
( c1 ,
c2 ,
c3
)
SELECT RowNum ,
message_id ,
severity
FROM MyRows;
SELECT *
FROM #table;
Try This :
WITH GetRecordByIncrement AS
(
SELECT
[RowNumber] = ROW_NUMBER() OVER (ORDER BY UserID ASC)
,[Column1]
,[Column2]
,[Column3]
FROM MySchema.MyTable
)
select * from GetRecordByIncrement where [RowNumber]<=desirednumber
I'm trying to make a stored sql server function that will return a table of median values that I can join back to another table, thusly:
CREATE FUNCTION [dbo].getmedian (#varPartionBy1 int,#varPartionBy2 int, #varForTieBreak int, #varForMeasure int)
RETURNS TABLE
AS
RETURN
(
SELECT
#varPartionBy1,
#varPartionBy2,
AVG(#varForMeasure)
FROM
(
SELECT
#varPartionBy1,
#varPartionBy2,
ROW_NUMBER() OVER (
PARTITION BY #varPartionBy1, #varPartionBy2
ORDER BY #varForMeasure ASC, #varForTieBreak ASC) AS RowAsc,
ROW_NUMBER() OVER (
PARTITION BY #varPartionBy1, #varPartionBy2
ORDER BY #varForMeasure ASC, #varForTieBreak DESC) AS RowDesc
from
[fakename].[dbo].[temptable] bp
) bp
WHERE
RowAsc IN (RowDesc, RowDesc - 1, RowDesc + 1)
GROUP BY #varPartionBy1, #varPartionBy2
)
GO
This is returning the error: "Msg 8155, Level 16, State 2, Procedure getmedian, Line 25
No column name was specified for column 1 of 'bp'." --indicating that I don't understand how to asign the table alias for a column in the context of a UDF, I guess.
What should I do to fix the error?
This is my very first USF so I appreciate any other helpful design insights you have while addressing them main question. Thanks for any help!
Where you have SELECT #varPartionBy1, #varPartionBy2 those need to have column names assigned to them. You can either assign them directly such as SELECT #varPartionBy1 AS varPartionBy1 or SELECT varPartionBy1 = #varPartionBy1 or you can specify it in the table alias ) bp(varPartionBy1, varPartionBy2,...
The correct function would likely be
CREATE FUNCTION [dbo].getmedian (#varPartionBy1 int,#varPartionBy2 int, #varForTieBreak int, #varForMeasure int)
RETURNS TABLE
AS
RETURN
(
SELECT
varPartionBy1,
varPartionBy2,
AVG(#varForMeasure) AS AvgVarForMeasure
FROM
(
SELECT
#varPartionBy1 AS varPartionBy1,
#varPartionBy2 As varPartionBy1,
ROW_NUMBER() OVER (
PARTITION BY #varPartionBy1, #varPartionBy2
ORDER BY #varForMeasure ASC, #varForTieBreak ASC) AS RowAsc,
ROW_NUMBER() OVER (
PARTITION BY #varPartionBy1, #varPartionBy2
ORDER BY #varForMeasure ASC, #varForTieBreak DESC) AS RowDesc
from
[fakename].[dbo].[temptable] bp
) bp
WHERE
RowAsc IN (RowDesc, RowDesc - 1, RowDesc + 1)
GROUP BY varPartionBy1, varPartionBy2
)
Well, once you get the syntax problem out of the way, your problems will not be over. For one, you can't really do what you're trying to do (pass in variables to the PARTITION BY and ORDER BY clauses). Those are just treated as constants, so the ROW_NUMBER() will be applied arbitrarily.
Observe what happens here:
DECLARE #foo SYSNAME = N'name';
SELECT name, foo = #foo, -- this is just a constant value, not a column
varASC = ROW_NUMBER() OVER (ORDER BY #foo ASC),
varDESC = ROW_NUMBER() OVER (ORDER BY #foo DESC),
colASC = ROW_NUMBER() OVER (ORDER BY name ASC),
colDESC = ROW_NUMBER() OVER (ORDER BY name DESC)
FROM sys.objects --WHERE is_ms_shipped = 0
ORDER BY varASC;
Partial results:
name foo varASC varDESC colASC colDESC
---- ---- ------ ------- ------ -------
t1 name 1 1 1 100
t2 name 2 2 2 99
t3 name 3 3 3 98
t4 name 4 4 4 97
t5 name 5 5 5 96
------ only column that deviates ----^^^^^^^
The variable value for #foo is the same on every single row, so, partitioning and ordering by that is completely meaningless.