I'm trying to read the top 100 items of a database table that is being used like a queue. As I do this I'm trying to mark the items as done like this:
UPDATE TOP(#qty)
QueueTable WITH (READPAST)
SET
IsDone = 1
OUTPUT
inserted.Id,
inserted.Etc
FROM
QueueTable
WHERE
IsDone = 0
ORDER BY
CreatedDate ASC;
The only problem is, according to UPDATE (Transact-SQL) on MSDN, the ORDER BY is not valid in an UPDATE and:
The rows referenced in the TOP expression used with INSERT, UPDATE, or
DELETE are not arranged in any order.
How can I achieve what I need which is to update the items at the top of the queue while also selecting them?
SQL Server allows you to update a derived table, CTE or view:
UPDATE x
SET
IsDone = 1
OUTPUT
inserted.Id,
inserted.Etc
FROM (
select TOP (N) *
FROM
QueueTable
WHERE
IsDone = 0
ORDER BY
CreatedDate ASC;
) x
No need to compute a set of IDs first. This is faster and usually has more desirable locking behavior.
Tested in SSMS, it works fine. You may need to do some modification accordingly.
--create table structure
create table #temp1 (
id int identity(1,1),
value int
)
go
--insert sample data
insert #temp1 values (1)
go 20
--below is solution
declare #qty int = 10
declare #cmd nvarchar(2000) =
N'update #temp1
set value= 100
output inserted.value
where id in
(
select top '+ cast(#qty as nvarchar(5)) +' id from #temp1
order by id
)';
execute sp_executesql #cmd
You can use ranking function (for example row_number).
update top (100) q
set IsDone = 1
output
inserted.Id,
inserted.Etc
from (
select *, row_number() over(order by CreatedDate asc, (select 0)) rn
from QueueTable) q
where rn <= 100
Related
I have a table [Order] that has records with sequential ID (in odd number only, i.e. 1,3,5,7...989, 991, 993, 995, 997, 999), it is seen that a few records were accidentally deleted and should be inserted back, first thing is to find out what records are missing in the current table, there are hundreds of records in this table
Don't know how to write the query, can anyone kindly help, please?
I am thinking if I have to write a stored procedure or function but would be better if I can avoid them for environment reasons.
Below peuso code is what I am thinking:
set #MaxValue = Max(numberfield)
set #TestValue = 1
open cursor on recordset ordered by numberfield
foreach numberfield
while (numberfield != #testvalue) and (#testvalue < #MaxValue) then
Insert #testvalue into #temp table
set #testvalue = #textvalue + 2
Next
Next
UPDATE:
Expected result:
Order ID = 7 should be picked up as the only missing record.
Update 2:
If I use
WHERE
o.id IS NULL;
It returns nothing:
Since I didn't get a response from you, in the comments, I've altered the script for you to fill in accordingly:
declare #id int
declare #maxid int
set #id = 1
select #maxid = max([Your ID Column Name]) from [Your Table Name]
declare #IDseq table (id int)
while #id < #maxid --whatever you max is
begin
insert into #IDseq values(#id)
set #id = #id + 1
end
select
s.id
from #IDseq s
left join [Your Table Name] t on s.id = t.[Your ID Column Name]
where t.[Your ID Column Name] is null
Where you see [Your ID Column Name], replace everything with your column name and the same goes for [Your Table Name].
I'm sure this will give you the results you seek.
We can try joining to a number table, which contains all the odd numbers which you might expect to appear in your own table.
DECLARE #start int = 1
DECLARE #end int = 1000
WITH cte AS (
SELECT #start num
UNION ALL
SELECT num + 2 FROM cte WHERE num < #end
)
SELECT num
FROM cte t
LEFT JOIN [Order] o
ON t.num = o.numberfield
WHERE
o.numberfield IS NULL;
I want to make a database query with pagination. So, I used a common-table expression and a ranked function to achieve this. Look at the example below.
declare #table table (name varchar(30));
insert into #table values ('Jeanna Hackman');
insert into #table values ('Han Fackler');
insert into #table values ('Tiera Wetherbee');
insert into #table values ('Hilario Mccray');
insert into #table values ('Mariela Edinger');
insert into #table values ('Darla Tremble');
insert into #table values ('Mammie Cicero');
insert into #table values ('Raisa Harbour');
insert into #table values ('Nicholas Blass');
insert into #table values ('Heather Hayashi');
declare #pagenumber int = 2;
declare #pagesize int = 3;
declare #total int;
with query as
(
select name, ROW_NUMBER() OVER(ORDER BY name ASC) as line from #table
)
select top (#pagesize) name from query
where line > (#pagenumber - 1) * #pagesize
Here, I can specify the #pagesize and #pagenumber variables to give me just the records that I want. However, this example (that comes from a stored procedure) is used to make a grid pagination in a web application. This web application requires to show the page numbers. For instance, if a have 12 records in the database and the page size is 3, then I'll have to show 4 links, each one representing a page.
But I can't do this without knowing how many records are there, and this example just gives me the subset of records.
Then I changed the stored procedure to return the count(*).
declare #pagenumber int = 2;
declare #pagesize int = 3;
declare #total int;
with query as
(
select name, ROW_NUMBER() OVER(ORDER BY name ASC) as line, total = count(*) over()from #table
)
select top (#pagesize) name, total from query
where line > (#pagenumber - 1) * #pagesize
So, along with each line, it will show the total number of records. But I didn't like it.
My question is if there's a better way (performance) to do this, maybe setting the #total variable without returning this information in the SELECT. Or is this total column something that won't harm the performance too much?
Thanks
Assuming you are using MSSQL 2012, you can use Offset and Fetch which cleans up server-side paging greatly. We've found performance is fine, and in most cases better. As far as getting the total column count, just use the window function below inline...it will not include the limits imposed by 'offset' and 'fetch'.
For Row_Number, you can use window functions the way you did, but I would recommend that you calculate that client side as (pagenumber*pagesize + resultsetRowNumber), so if you're on the 5th page of 10 results and on the third row you would output row 53.
When applied to an Orders table with about 2 million orders, I found the following:
FAST VERSION
This ran in under a second. The nice thing about it is that you can do your filtering in the common table expression once and it applies both to the paging process and the count. When you have many predicates in the where clause, this keeps things simple.
declare #skipRows int = 25,
#takeRows int = 100,
#count int = 0
;WITH Orders_cte AS (
SELECT OrderID
FROM dbo.Orders
)
SELECT
OrderID,
tCountOrders.CountOrders AS TotalRows
FROM Orders_cte
CROSS JOIN (SELECT Count(*) AS CountOrders FROM Orders_cte) AS tCountOrders
ORDER BY OrderID
OFFSET #skipRows ROWS
FETCH NEXT #takeRows ROWS ONLY;
SLOW VERSION
This took about 10 sec, and it was the Count(*) that caused the slowness. I'm surprised this is so slow, but I suspect it's simply calculating the total for each row. It's very clean though.
declare #skipRows int = 25,
#takeRows int = 100,
#count int = 0
SELECT
OrderID,
Count(*) Over() AS TotalRows
FROM Location.Orders
ORDER BY OrderID
OFFSET #skipRows ROWS
FETCH NEXT #takeRows ROWS ONLY;
CONCLUSION
We've gone through this performance tuning process before and actually found that it depended on the query, predicates used, and indexes involved. For instance, the second we introduced a view it chugged, so we actually query off the base table and then join up the view (which includes the base table) and it actually performs very well.
I would suggest having a couple of straight-forward strategies and applying them to high-value queries that are chugging.
DECLARE #pageNumber INT = 1 ,
#RowsPerPage INT = 20
SELECT *
FROM TableName
ORDER BY Id
OFFSET ( ( #pageNumber - 1 ) * #RowsPerPage ) ROWS
FETCH NEXT #RowsPerPage ROWS ONLY;
What if you calculate the count beforehand?
declare #pagenumber int = 2;
declare #pagesize int = 3;
declare #total int;
SELECT #total = count(*)
FROM #table
with query as
(
select name, ROW_NUMBER() OVER(ORDER BY name ASC) as line from #table
)
select top (#pagesize) name, #total total from query
where line > (#pagenumber - 1) * #pagesize
Another way, is to calculate max(line). Check the link
Return total records from SQL Server when using ROW_NUMBER
UPD:
For single query, check marc_s's answer on the link above.
with query as
(
select name, ROW_NUMBER() OVER(ORDER BY name ASC) as line from #table
)
select top (#pagesize) name,
(SELECT MAX(line) FROM query) AS total
from query
where line > (#pagenumber - 1) * #pagesize
#pagenumber=5
#pagesize=5
Create a common table expression and write logic like this
Between ((#pagenumber-1)*(#pagesize))+1 and (#pagenumber *#pagesize)
There are many way we can achieve pagination: I hope this information is useful to you and others.
Example 1: using offset-fetch next clause. introduce in 2005
declare #table table (name varchar(30));
insert into #table values ('Jeanna Hackman');
insert into #table values ('Han Fackler');
insert into #table values ('Tiera Wetherbee');
insert into #table values ('Hilario Mccray');
insert into #table values ('Mariela Edinger');
insert into #table values ('Darla Tremble');
insert into #table values ('Mammie Cicero');
insert into #table values ('Raisa Harbour');
insert into #table values ('Nicholas Blass');
insert into #table values ('Heather Hayashi');
declare #pagenumber int = 1
declare #pagesize int = 3
--this is a CTE( common table expression and this is introduce in 2005)
with query as
(
select ROW_NUMBER() OVER(ORDER BY name ASC) as line, name from #table
)
--order by clause is required to use offset-fetch
select * from query
order by name
offset ((#pagenumber - 1) * #pagesize) rows
fetch next #pagesize rows only
Example 2: using row_number() function and between
declare #table table (name varchar(30));
insert into #table values ('Jeanna Hackman');
insert into #table values ('Han Fackler');
insert into #table values ('Tiera Wetherbee');
insert into #table values ('Hilario Mccray');
insert into #table values ('Mariela Edinger');
insert into #table values ('Darla Tremble');
insert into #table values ('Mammie Cicero');
insert into #table values ('Raisa Harbour');
insert into #table values ('Nicholas Blass');
insert into #table values ('Heather Hayashi');
declare #pagenumber int = 2
declare #pagesize int = 3
SELECT *
FROM
(select ROW_NUMBER() OVER (ORDER BY PRODUCTNAME) AS RowNum, * from Products)
as Prodcut
where RowNum between (((#pagenumber - 1) * #pageSize )+ 1)
and (#pagenumber * #pageSize )
I hope these will be helpful to all
I don't like other solutions for being too complex, so here is my version.
Execute three select queries in one go and use output parameters for getting the count values. This query returns the total count, the filter count, and the page rows. It supports sorting, searching, and filtering the source data. It's easy to read and modify.
Let's say you have two tables with one-to-many relationship, items and their prices changed over time so the example query is not too trivial.
create table shop.Items
(
Id uniqueidentifier not null primary key,
Name nvarchar(100) not null,
);
create table shop.Prices
(
ItemId uniqueidentifier not null,
Updated datetime not null,
Price money not null,
constraint PK_Prices primary key (ItemId, Updated),
constraint FK_Prices_Items foreign key (ItemId) references shop.Items(Id)
);
Here is the query:
select #TotalCount = count(*) over()
from shop.Items i;
select #FilterCount = count(*) over()
from shop.Items i
outer apply (select top 1 p.Price, p.Updated from shop.Prices p where p.ItemId = i.Id order by p.Updated desc) as p
where (#Search is null or i.Name like '%' + #Search + '%')/**where**/;
select i.Id as ItemId, i.Name, p.Price, p.Updated
from shop.Items i
outer apply (select top 1 p.Price, p.Updated from shop.Prices p where p.ItemId = i.Id order by p.Updated desc) as p
where (#Search is null or i.Name like '%' + #Search + '%')/**where**/
order by /**orderby**/i.Id
offset #SkipCount rows fetch next #TakeCount rows only;
You need to provide the following parameters to the query:
#SkipCount - how many records to skip, calculated from the page number.
#TakeCount - how many records to return, calculated from or equal to the page size.
#Search - a text to search for in some columns, provided by the grid search box.
#TotalCount - the total number of records in the data source, the output parameter.
#FilterCount - the number of records after the search and filtering operations, the output parameter.
You can replace /**orderby**/ comment with the list of columns and their ordering directions if the grid must support sorting the rows by columns. you get this info from the grid and translate it to an SQL expression. We still need to order the records by some column initially, I usually use ID column for that.
If the grid must support filtering data by each column individually, you can replace /**where**/ comment with an SQL expression for that.
If the user is not searching and filtering the data, but only clicks through the grid pages, this query doesn't change at all and the database server executes it very quickly.
I have a TSQL code that relies on a stored procedure to select a row.
When I'm implementing a more complex TSQL script that will select many rows based on a condition, instead of having one result set of x rows I'm ending up with x result sets containing one row.
My first question is: is it a concern or the performances are close to what I would get with one result set of x rows?
Second question: does anybody think that a temporary table where my stored procedure insert the result (instead of a select) should be faster?
Edit:
Basically this stored procedure select all the items of a given HierarchicalObject.
ALTER PROCEDURE [dbo].[MtdMdl_HierarchicalObject_Collection_Items]
#relatedid int
AS
BEGIN
SET NOCOUNT ON
declare #curkeyid int
declare cur CURSOR static read_only LOCAL
for select distinct [Id] from MtdMdl_Item where [Owner] = #relatedid
open cur
fetch next
from cur into #curkeyid
while ##FETCH_STATUS = 0
BEGIN
-- select the item row from its ID
exec MtdMdl_Item_ItemBase_Read #keyid = #curkeyid
fetch next
from cur into #curkeyid
END
close cur
deallocate cur
END
ALTER PROCEDURE [dbo].[MtdMdl_Item_ItemBase_Read]
#keyid int
AS
BEGIN
SET NOCOUNT ON
SELECT TOP(1) [Id], [TimeStamp], [Name], [Owner], [Value]
FROM [MtdMdl_Item]
WHERE ([Id]=#keyid)
ORDER BY TimeStamp Desc
END
For sure you should better place all single output rows into resulting temporary table before selecting final recordset. There is no reason currently in your code to return one recorset containing all separate rows from iteration over cursor with sp;
Your MtdMdl_Item_ItemBase_Read is relevant a bit because after turning it into function you can avoid sp+cursor and complete the task with one single query using inline function.
upd
According to your data structure I understand that your [Id] is not unique which is source of confusing.
There are many ways to do what you need but here is example of one query even avoiding CTE for temporary result:
DECLARE #relatedid int = 2
SELECT top(1) WITH ties
[Id], [TimeStamp], [Name], [Owner], [Value]
FROM MtdMdl_Item
WHERE [Owner]=#relatedid
ORDER BY row_number() over(partition BY [Id] ORDER BY [TimeStamp] DESC)
Consider this SQL Fiddle as demo.
upd2
Example with inline table function:
CREATE FUNCTION MtdMdl_Item_ItemBase_Read (#keyid int)
RETURNS TABLE
AS
RETURN
(
SELECT TOP(1) [Id], [TimeStamp], [Name], [Owner], [Value]
FROM [MtdMdl_Item]
WHERE ([Id]=#keyid)
ORDER BY TimeStamp Desc
)
GO
DECLARE #relatedid int = 2
SELECT DISTINCT A.[Id],B.* FROM MtdMdl_Item A
OUTER apply (SELECT * FROM MtdMdl_Item_ItemBase_Read(A.[Id])) B
WHERE A.[Owner] = #relatedid
SQL Fiddle 2
Your answer is in below link you should use GROUP BY instead of DISTINCT
SQL/mysql - Select distinct/UNIQUE but return all columns?
And in below line of your code enter list of columns you want in your result
declare cur CURSOR static read_only LOCAL
for select distinct [Id] from MtdMdl_Item where [Owner] = #relatedid
So your query will be
declare cur CURSOR static read_only LOCAL
for select rows,you,want,in,result from MtdMdl_Item where [Owner] = #relatedid Order By [column name you want to be distinct]
In my DB I have two tables Items(Id, ..., ToatlViews int) and ItemViews (id, ItemId, Timestamp)
In ItemViews table I store all views of an item as they come to the site. From time to time I want to call a stored procedure to update Items.ToatlViews field. I tried to do this SP using a cursor ... but the update statement is wrong. Can you help me to correct it? Can I do this without cursor?
CREATE PROCEDURE UpdateItemsViews
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #currentItemId int
DECLARE #currentItemCursor CURSOR
SET #currentItemCursor = CURSOR FOR SELECT Id FROM dbo.Items
OPEN #currentItemCursor
FETCH NEXT FROM #currentItemCursor INTO #currentItemId
WHILE ##FETCH_STATUS = 0
BEGIN
Update dbo.Items set TotalViews = count(*)
from dbo.ItemViews where ItemId=#currentItemId
FETCH NEXT FROM #currentItemCursor INTO #currentItemId
END
END
GO
You can use a direct UPDATE statement
update Items set TotalViews =
(select COUNT(id) from ItemViews where ItemViews.ItemId = Items.Id)
You might want to test performance for the various ways to do this, if that's important.
You could use update ... from instead of a cursor:
update i
set TotalViews = iv.cnt
from dbo.Item i
join (
select ItemId
, count(*) as cnt
from dbo.ItemViews
group by
ItemId
) iv
on i.Id = iv.ItemId
;WITH x AS
(
SELECT ItemID, c = COUNT(*)
FROM dbo.ItemViews
GROUP BY ItemID
)
UPDATE i
SET TotalViews = x.c
FROM dbo.Items AS i
INNER JOIN x
ON x.ItemID = i.ItemID;
But why do you want to store this value, when you can always get the count at runtime? You're going to have to run this update statement every time you touch the ItemViews table in any way, otherwise the count stored with Items is going to be incorrect.
What you may consider doing instead is setting up an indexed view:
CREATE VIEW dbo.ItemViewCount
WITH SCHEMABINDING
AS
SELECT ItemID, ItemCount = COUNT_BIG(*)
FROM dbo.ItemViews
GROUP BY ItemID;
GO
CREATE UNIQUE CLUSTERED INDEX x ON dbo.ItemViewCount(ItemID);
Now you can join to the view in your queries and know that the count is always up to date (without paying the penalty of scanning for the count of each item). The downside to the indexed view is that you pay that cost incrementally when there are inserts/updates/deletes to the ItemViews table.
I found this question / answer a year after it was written and answered. the answer was okay, but I was after something a bit more automatic. I ended up writing a trigger to automatically recalculate the column when a relevant row in the other table was inserted, deleted or updated.
I think it's a better solution than running something manually to do the recalculation as there isn't any possibility of someone forgetting to run the code:
CREATE TRIGGER [dbo].[TriggerItemTotalViews]
ON [dbo].[ItemViews]
AFTER INSERT, DELETE, UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE [Items]
SET [TotalViews] =
(
SELECT COUNT(id)
FROM [ItemViews]
WHERE [ItemViews].[ItemId] = [Items].[ItemId]
)
WHERE [Items].[ItemId] IN
(
SELECT [ItemId] FROM [INSERTED]
UNION
SELECT [ItemId] FROM [DELETED]
)
END
Same but different:
declare #productId int = 24;
declare #classificationTypeId int = 86;
update s
set CounterByProductAndClassificationType = row_num
from Samples s
join
(
select row_number() over (order by (select Id)) row_num, Id
from Samples
where
ProductId = #productId and
ClassificationTypeId = #classificationTypeId
) s_row on s.Id = s_row.Id
For who need to include zero count too
UPDATE Items as i,
(SELECT
i.Id as Id, COUNT(iv.ItemId) AS c
FROM
Items AS i
LEFT JOIN ItemViews AS iv ON i.Id = iv.ItemId
GROUP BY i.Id) AS ic
SET
i.TotalViews = ic.c
WHERE
i.Id = ic.Id
I would like to know if there is a way to use an order by clause when updating a table. I am updating a table and setting a consecutive number, that's why the order of the update is important. Using the following sql statement, I was able to solve it without using a cursor:
DECLARE #Number INT = 0
UPDATE Test
SET #Number = Number = #Number +1
now what I'd like to to do is an order by clause like so:
DECLARE #Number INT = 0
UPDATE Test
SET #Number = Number = #Number +1
ORDER BY Test.Id DESC
I've read: How to update and order by using ms sql The solutions to this question do not solve the ordering problem - they just filter the items on which the update is applied.
Take care,
Martin
No.
Not a documented 100% supported way. There is an approach sometimes used for calculating running totals called "quirky update" that suggests that it might update in order of clustered index if certain conditions are met but as far as I know this relies completely on empirical observation rather than any guarantee.
But what version of SQL Server are you on? If SQL2005+ you might be able to do something with row_number and a CTE (You can update the CTE)
With cte As
(
SELECT id,Number,
ROW_NUMBER() OVER (ORDER BY id DESC) AS RN
FROM Test
)
UPDATE cte SET Number=RN
You can not use ORDER BY as part of the UPDATE statement (you can use in sub-selects that are part of the update).
UPDATE Test
SET Number = rowNumber
FROM Test
INNER JOIN
(SELECT ID, row_number() OVER (ORDER BY ID DESC) as rowNumber
FROM Test) drRowNumbers ON drRowNumbers.ID = Test.ID
Edit
Following solution could have problems with clustered indexes involved as mentioned here. Thanks to Martin for pointing this out.
The answer is kept to educate those (like me) who don't know all side-effects or ins and outs of SQL Server.
Expanding on the answer gaven by Quassnoi in your link, following works
DECLARE #Test TABLE (Number INTEGER, AText VARCHAR(2), ID INTEGER)
DECLARE #Number INT
INSERT INTO #Test VALUES (1, 'A', 1)
INSERT INTO #Test VALUES (2, 'B', 2)
INSERT INTO #Test VALUES (1, 'E', 5)
INSERT INTO #Test VALUES (3, 'C', 3)
INSERT INTO #Test VALUES (2, 'D', 4)
SET #Number = 0
;WITH q AS (
SELECT TOP 1000000 *
FROM #Test
ORDER BY
ID
)
UPDATE q
SET #Number = Number = #Number + 1
The row_number() function would be the best approach to this problem.
UPDATE T
SET T.Number = R.rowNum
FROM Test T
JOIN (
SELECT T2.id,row_number() over (order by T2.Id desc) rowNum from Test T2
) R on T.id=R.id
update based on Ordering by the order of values in a SQL IN() clause
Solution:
DECLARE #counter int
SET #counter = 0
;WITH q AS
(
select * from Products WHERE ID in (SELECT TOP (10) ID FROM Products WHERE ID IN( 3,2,1)
ORDER BY ID DESC)
)
update q set Display= #counter, #counter = #counter + 1
This updates based on descending 3,2,1
Hope helps someone.
I had a similar problem and solved it using ROW_NUMBER() in combination with the OVER keyword. The task was to retrospectively populate a new TicketNo (integer) field in a simple table based on the original CreatedDate, and grouped by ModuleId - so that ticket numbers started at 1 within each Module group and incremented by date. The table already had a TicketID primary key (a GUID).
Here's the SQL:
UPDATE Tickets SET TicketNo=T2.RowNo
FROM Tickets
INNER JOIN
(select TicketID, TicketNo,
ROW_NUMBER() OVER (PARTITION BY ModuleId ORDER BY DateCreated) AS RowNo from Tickets)
AS T2 ON T2.TicketID = Tickets.TicketID
Worked a treat!
I ran into the same problem and was able to resolve it in very powerful way that allows unlimited sorting possibilities.
I created a View using (saving) 2 sort orders (*explanation on how to do so below).
After that I simply applied the update queries to the View created and it worked great.
Here are the 2 queries I used on the view:
1st Query:
Update MyView
Set SortID=0
2nd Query:
DECLARE #sortID int
SET #sortID = 0
UPDATE MyView
SET #sortID = sortID = #sortID + 1
*To be able to save the sorting on the View I put TOP into the SELECT statement. This very useful workaround allows the View results to be returned sorted as set when the View was created when the View is opened. In my case it looked like:
(NOTE: Using this workaround will place an big load on the server if using a large table and it is therefore recommended to include as few fields as possible in the view if working with large tables)
SELECT TOP (600000)
dbo.Items.ID, dbo.Items.Code, dbo.Items.SortID, dbo.Supplier.Date,
dbo.Supplier.Code AS Expr1
FROM dbo.Items INNER JOIN
dbo.Supplier ON dbo.Items.SupplierCode = dbo.Supplier.Code
ORDER BY dbo.Supplier.Date, dbo.Items.ID DESC
Running: SQL Server 2005 on a Windows Server 2003
Additional Keywords: How to Update a SQL column with Ascending or Descending Numbers - Numeric Values / how to set order in SQL update statement / how to save order by in sql view / increment sql update / auto autoincrement sql update / create sql field with ascending numbers
SET #pos := 0;
UPDATE TABLE_NAME SET Roll_No = ( SELECT #pos := #pos + 1 ) ORDER BY First_Name ASC;
In the above example query simply update the student Roll_No column depending on the student Frist_Name column. From 1 to No_of_records in the table. I hope it's clear now.
IF OBJECT_ID('tempdb..#TAB') IS NOT NULL
BEGIN
DROP TABLE #TAB
END
CREATE TABLE #TAB(CH1 INT,CH2 INT,CH3 INT)
DECLARE #CH2 INT = NULL , #CH3 INT=NULL,#SPID INT=NULL,#SQL NVARCHAR(4000)='', #ParmDefinition NVARCHAR(50)= '',
#RET_MESSAGE AS VARCHAR(8000)='',#RET_ERROR INT=0
SET #ParmDefinition='#SPID INT,#CH2 INT OUTPUT,#CH3 INT OUTPUT'
SET #SQL='UPDATE T
SET CH1=#SPID,#CH2= T.CH2,#CH3= T.CH3
FROM #TAB T WITH(ROWLOCK)
INNER JOIN (
SELECT TOP(1) CH1,CH2,CH3
FROM
#TAB WITH(NOLOCK)
WHERE CH1 IS NULL
ORDER BY CH2 DESC) V ON T.CH2= V.CH2 AND T.CH3= V.CH3'
INSERT INTO #TAB
(CH2 ,CH3 )
SELECT 1,2 UNION ALL
SELECT 2,3 UNION ALL
SELECT 3,4
BEGIN TRY
WHILE EXISTS(SELECT TOP 1 1 FROM #TAB WHERE CH1 IS NULL)
BEGIN
EXECUTE #RET_ERROR = sp_executesql #SQL, #ParmDefinition,#SPID =##SPID, #CH2=#CH2 OUTPUT,#CH3=#CH3 OUTPUT;
SELECT * FROM #TAB
SELECT #CH2,#CH3
END
END TRY
BEGIN CATCH
SET #RET_ERROR=ERROR_NUMBER()
SET #RET_MESSAGE = '#ERROR_NUMBER : ' + CAST(ERROR_NUMBER() AS VARCHAR(255)) + '#ERROR_SEVERITY :' + CAST( ERROR_SEVERITY() AS VARCHAR(255))
+ '#ERROR_STATE :' + CAST(ERROR_STATE() AS VARCHAR(255)) + '#ERROR_LINE :' + CAST( ERROR_LINE() AS VARCHAR(255))
+ '#ERROR_MESSAGE :' + ERROR_MESSAGE() ;
SELECT #RET_ERROR,#RET_MESSAGE;
END CATCH