Update rows starting for specific number - sql

I have a number into variable like:
DECLARE #CurrentLastFolio INT = (SELECT TOP 1 Folio FROM myTable ORDER BY folio DESC)
So supposing we have number 1004 into this variable.
Into another query I have some rows with folio = 0:
SELECT * FROM myTable WHERE folio = 0
That I want to do is to update this records with #CurrentLastFolio + 1 on each row. So first row should have Folio = 1005, next 1006 and so on.
How can I achieve that?

You can use the following solution, updating the variable on the UPDATE too:
DECLARE #CurrentLastFolio INT = (SELECT MAX(folio) FROM table_name);
UPDATE table_name
SET folio = #CurrentLastFolio, #CurrentLastFolio += 1
WHERE folio = 0
demo on dbfiddle.uk
Arithmetic overflow error converting expression to data type int:
In case your values get larger than 2,147,483,647 (maximum value of INT data type) you need to use BIGINT intead of INT to store (column folio) or increment the value (variable #CurrentLastFolio):
-- you need to use BIGINT on the table.
CREATE TABLE table_name (
folio BIGINT
)
-- you need to use BIGINT on the variable.
DECLARE #CurrentLastFolio BIGINT = (SELECT MAX(folio) from table_name);
-- now you can count and store numbers larger than INT maximum value.
UPDATE table_name
SET folio = #CurrentLastFolio, #CurrentLastFolio += 1
WHERE folio = 0
demo on dbfiddle.uk

Check this:
declare #CurrentLastFolio int = (SELECT TOP 1 Folio from myTable order by folio desc);
with tbl AS
(
SELECT * ,ROW_NUMBER() OVER( order by c1 ) AS rn
FROM myTable
)
update tbl set folio = rn + #x
Example Implementation for easy understanding
create table t (c1 int);
GO
✓
insert into t values (1), (2), (3)
GO
3 rows affected
declare #x int = 1000;
with tbl AS
(
SELECT * ,ROW_NUMBER() OVER( order by c1 ) AS rn
FROM t
)
update tbl set c1 = rn + #x
GO
3 rows affected
select * from t
GO
| c1 |
| ---: |
| 1001 |
| 1002 |
| 1003 |
db<>fiddle here

Related

Inserting not calculated Id in table transact SQL

I have a stored procedure where I receive data as JSON from a API in C#. I insert the data into two tables like this:
INSERT INTO dbo.ServiceRequestHeader(SubscriptionId, CustomerAccountId, ModifiedBy)
OUTPUT Inserted.ServiceRequestHeaderId INTO #TempT
SELECT
SubscriptionId,
CustomerAccountId,
ModifiedBy
FROM
OpenJson(#JsonServiceRequest)
WITH
(SubscriptionId TinyInt,
CustomerAccountId Int)
SELECT #TempId = Id FROM #TempT
INSERT INTO dbo.ServiceRequest(ServiceRequestId, ServiceRequestHeaderId, SubscriptionId)
SELECT
#TempId, -- <= Here I need to modify the serviceRequestHeaderId
#TempId,
SubscriptionId
FROM
OpenJson(#JsonServiceRequest, '$.ServiceRequest')
WITH (SubscriptionId TinyInt,
...)
The thing is that the serviceRequestId is not a calculated field and it's a special case that depends on ServiceRequestHeaderId.
Example:
If ServiceRequestHeaderId = 1000 the ServiceRequestId would be 1000 001, 1000 002... N...
This is where I can't come with a way to do it
You can generate servicerequestids as given below. I am using FORMAT function with 000 for padding with 0 till 3 digits. If you want four digits, use 0000.
SELECT #TempId = Id FROM #TempT
INSERT INTO dbo.ServiceRequest(ServiceRequestId, ServiceRequestHeaderId, SubscriptionId)
SELECT
CONCAT(#TempId,FORMAT(ROW_NUMBER() OVER(ORDER BY (SELECT null)),'000')) AS ServiceRequestId, -- <= Here I need to modify the serviceRequestHeaderId
#TempId,
SubscriptionId
FROM
OpenJson(#JsonServiceRequest, '$.ServiceRequest')
WITH (SubscriptionId TinyInt,
...)
You will get something like below:
+------------------+
| ServiceRequestId |
+------------------+
| 1000001 |
| 1000002 |
| 1000003 |
+------------------+
Use a CTE to calculate a row number per request and then build the id from it e.g.
with MyCTE as (
select
SubscriptionId
-- Order by whatever makes business sense to you
, row_number() over (order by SubscriptionId) rn
from openjson(#JsonServiceRequest, '$.ServiceRequest')
with (
SubscriptionId tinyint,
...
)
)
insert into dbo.ServiceRequest (ServiceRequestId, ServiceRequestHeaderId, SubscriptionId)
-- Put whatever logic you like here to calculate a row number based id
select convert(varchar(4),#TempId) + ' ' + case when rn >= 100 then convert(varchar(3),rn) when rn > 10 then '0' + convert(varchar(2),rn) else '00' + convert(varchar(1),rn) end
, #TempId, SubscriptionId
from MyCTE;

SQL - how to update a column with each row value incremented by 1?

For the selected rows in a column, how to update each row sequentially from the beginning to the end, with each row value incremented by 1 (or certain number). I know this can be done in excel in few seconds but I could figure out how to achieve in SQL server. For instance:
customer id is NULL now
update customer id with every row incremented by 1 (i.e. first row = 1, second row = 2, .....nth row = n)
ship-to party customer id
0002018092 NULL
0002008127 NULL
0002000129 NULL
0002031592 NULL
0002034232 NULL
desired output
ship-to party customer id
0002018092 1
0002008127 2
0002000129 3
0002031592 4
0002034232 5
Also, for the selected rows in a column, how to update each row with the row number? I know there is a row_number() function but didn't succeed in producing the desired result. for instance
column A is NULL now
update Column A with every row incremented by 1 (i.e. first row = row number 1, second row = row number 2, .....nth row = row number n)
Any demonstration would be very helpful.thkans
example : suppose I want to add a value to each value in column SomeIntField in table tblUser
there are 2 ways of doing this easy
first: this just adds value 1 to each column SomeIntField
update tblUser set SomeIntField = SomeIntField + 1
second : this adds an incrementing value, the first row gets +1, second gets +2, and so on...
declare #number int = 0
update tblUser
set #number = #number + 1,
SomeIntField = isnull(SomeIntField, 0) + #Number
EDIT: based on your last comment this might be what you want
declare #table table (shiptoparty varchar(50), customer_id int)
insert into #Table (shiptoparty, customer_id)
values ('0002018092', NULL), ('0002008127', NULL), ('0002000129', NULL), ('0002031592', NULL), ('0002034232', NULL)
declare #number int = 0
update #table
set #number = #number + 1,
customer_id = isnull(customer_id, 0) + #Number
select * from #table
The result of this is :
shiptoparty | customer_id
----------- | -----------
0002018092 | 1
0002008127 | 2
0002000129 | 3
0002031592 | 4
0002034232 | 5
Rather than using a self referencing variable, use a CTE:
WITH CTE AS (
SELECT [Your Incrementing Column],
ROW_NUMBER() OVER (ORDER BY [Columns to Order By]) AS RN
FROM YourTable)
UPDATE CTE
SET [Your Incrementing Column] = RN;
Edit: To prove a point that ALL rows will be updated:
CREATE TABLE #Sample (String varchar(50),
IncrementingInt int);
INSERT INTO #Sample (String)
VALUES ('sdkfjasdf'),
('dfydsfdfg'),
('sdfgsdfg45yfg'),
('dfgf54d'),
('dsft43tdc'),
('f6gytrntrfu7m45'),
('5d6f45wgby54'),
('g34h636j'),
('jw'),
('h6nw54m'),
('g54j747jm5e5f4w5gsft'),
('ns67mw54mk8o7hr'),
('h45j4w5h4');
SELECT *
FROM #Sample;
WITH CTE AS(
SELECT IncrementingInt,
ROW_NUMBER() OVER (ORDER BY String) AS RN
FROM #Sample)
UPDATE CTE
SET IncrementingInt = RN;
SELECT *
FROM #Sample;
DROP TABLE #Sample;
GO
To update each row with row number
Try below
CREATE TABLE tmp(Id INT IDENTITY(1,1), Value INT)
INSERT INTO tmp(value) VALUES(1),(2),(3),(4),(5)
UPDATE T
SET
T.Value = B.RowNo
FROM tmp AS T
INNER JOIN (SELECT Id, ROW_NUMBER()OVER(ORDER BY Id) AS RowNo FROM tmp)AS B
ON T.Id = B.Id
Don't think very complex. Try the simple method given below
alter table table_name drop column customer_id
go
alter table table_name add id customer_id IDENTITY(1,1)
go
First problem:
you want to increase values in every row in certain column by 1 (or other nuber), try this:
update TABLE_NAME set column_to_increase = column_to_increase + 1
Second problem:
you want to get row number for only certain rows. Solution: first create column holding all row numbers, then get the rows:
select * from (
select column1, column2, ..., columnN, row_number() over (order by (select null)) as [rn] from MY_TABLE
) where *condition*
FYI: select null in over clause does exactly nothing, it's just there, because window functions (such as row_number) have to have over clause and some of them require order by.

T-SQL: Efficient way to add up column values

Now I'm sure this has been asked and superbly been answered on here. However, I am unable to find the answer since it touches many keywords.
I basically want to replace a table of the form:
Type amount param note
7 2 str1 NULL
42 12 str2 NULL
128 7 str3 samplenote
42 12 NULL NULL
101 4 str4 NULL
42 12 NULL NULL
7 1 str1 samplenote
128 2 str5 NULL
with a table like:
Type amount param note
7 3 str1 combined
42 36 NULL combined
128 9 NULL combined
101 4 str4 combined
In words, I seek to sum up the amount parameter based on its type while declaring param = NULL for all "unclear" fields. (param should be NULL when the param values of combined Types have more than one different content; else, param should have the original content.)
With my python background, I tackled this task with a for loop approach, iterating through the types, adding a new row for every type with summed up amount and note = 'combined', to then delete the remaining rows (see below). There has to be a more efficient way with some JOIN statement I'm sure. But how would that look like?
FYI, this is the solution I am working on (not functioning yet!):
/*** dbo.sourcetable holds all possible Type values ***/
CREATE PROCEDURE [sumup]
AS
BEGIN
DECLARE #i int = (SELECT TOP (1) Type FROM [dbo].[sourcetable] ORDER BY Type)
DECLARE #MaxType int = (SELECT TOP (1) Type FROM [dbo].[sourcetable] ORDER BY Type DESC)
DECLARE #sum int
BEGIN TRY
WHILE #i <= #MaxType
BEGIN
IF EXISTS (SELECT * FROM [dbo].[worktable] WHERE Type = #i)
BEGIN
SET #sum = (SELECT SUM(amount) FROM [dbo].[worktable] WHERE Type = #i)
BEGIN
WITH cte AS (SELECT * FROM [dbo].[worktable] WHERE Type = #i)
INSERT INTO [dbo].[worktable]
([Type]
,[amount]
,[param]
,[note]
SELECT
cte.Type
,#sum
,cte.param
,'combined'
FROM cte
END
DELETE FROM [dbo].[worktable] WHERE Type = #i AND ISNULL([note],'') <> 'combined'
END
SET #i = #i + 1
END
END TRY
BEGIN CATCH
-- some errorlogging code
END CATCH
END
GO
This can be achieved with a single select statement.
If you require your combined flag to only apply to where more than one row has been combined, add another case expression checking the result of either a count(1) for rows combined or count(distinct param) for unique param values combined:
declare #t as table(type int, amount int, param varchar(15), note varchar(15));
insert into #t values (7,2,'str1',NULL),(42,12,'str2',NULL),(128,7,'str3','samplenote'),(42,12,NULL,NULL),(101,4,'str4',NULL),(42,12,NULL,NULL),(7,1,'str1','samplenote'),(128,2,'str5',NULL);
select type
,sum(amount) as amount
,case when count(distinct isnull(param,'')) = 1
then max(param)
else null
end as param
,'combined' as note
from #t
group by type
order by type;
Output:
+------+--------+-------+----------+
| type | amount | param | note |
+------+--------+-------+----------+
| 7 | 3 | str1 | combined |
| 42 | 36 | NULL | combined |
| 101 | 4 | str4 | combined |
| 128 | 9 | NULL | combined |
+------+--------+-------+----------+
I am doing this way from keyboard, but this may work or be close to what you want
Select type , amount , iif( dc=1,p,null) param, 'combined' note
from
(
Select type, sum(amount) amount,
count(distinct Param) dc,max(Param) p
From ....
Group by type
) x
Here is a possible solution:
declare #tbl as table (
type int
,amount int
,param varchar(15)
,note varchar(15)
)
insert into #tbl values (7,2,'str1',NULL)
insert into #tbl values (42,12,'str2',NULL)
insert into #tbl values (128,7,'str3','samplenote')
insert into #tbl values (42,12,NULL,NULL)
insert into #tbl values (101,4,'str4',NULL)
insert into #tbl values (42,12,NULL,NULL)
insert into #tbl values (7,1,'str1','samplenote')
insert into #tbl values (128,2,'str5',NULL)
;WITH CTE AS (
SELECT
type
,SUM(AMOUNT) AS amount
,COUNT(DISTINCT ISNULL(param, 'dummy value')) AS ParamNo
,MAX(Param) AS Param
FROM #tbl
GROUP BY type
) SELECT
type
,amount
,CASE WHEN ParamNo = 1 THEN Param ELSE NULL END AS Param
,'combined' AS note
FROM CTE
This should work:
Select Type, sum(amount) as amount, count(distinct param)
, case when count(distinct param) = 1 then max(param) end as param,
'Combined' as note
From
mytable
Group By Type

Increment each field in a column by 1 - SQL Server 2008

I need to increment each field in a column by 1 starting from 2866. I've built the following query, but all it does is set each field to 2867 as opposed to 2868, 2869 etc...
DECLARE #a int
SET #a = 2866
UPDATE view_kantech_matched SET image_id = #a + 1
WHERE image_id = null
Any suggestions? Thanks
The general structure for doing this would be:
;WITH Numbered as (
SELECT *,ROW_NUMBER() OVER (ORDER BY <some column>) rn
FROM view_kantech_matched
WHERE image_id is NULL
)
UPDATE Numbered SET image_id = 2865 + rn
But I don't know what <some column> would be.
DECLARE #a int
SET #a = 2866
UPDATE view_kantech_matched SET image_id = #a, #a=#a + 1
WHERE image_id = null
If you want to update it to a value that starts at 2866 and increaments with every row you have to specify the column(s) to be used for the ordering.
Then you can use ROW_NUMBER:
WITH NoImageIDS AS
(
SELECT vkm.*, RN = ROW_NUMBER() OVER (ORDER BY AnyColumn ASC)
FROM dbo.view_kantech_matched vkm
WHERE image_id IS NULL
)
UPDATE NoImageIDS SET image_id = RN + 2866

Sequential numbers randomly selected and added to table

The SO Question has lead me to the following question.
If a table has 16 rows I'd like to add a field to the table with the numbers 1,2,3,4,5,...,16 arranged randomly i.e in the 'RndVal' field for row 1 this could be 2, then for row 2 it could be 5 i.e each of the 16 integers needs to appear once without repetition.
Why doesn't the following work? Ideally I'd like to see this working then to see alternative solutions.
This creates the table ok:
IF OBJECT_ID('tempdb..#A') IS NOT NULL BEGIN DROP TABLE #A END
IF OBJECT_ID('tempdb..#B') IS NOT NULL BEGIN DROP TABLE #B END
IF OBJECT_ID('tempdb..#C') IS NOT NULL BEGIN DROP TABLE #C END
IF OBJECT_ID('tempdb..#myTable') IS NOT NULL BEGIN DROP TABLE #myTable END
CREATE TABLE #B (B_ID INT)
CREATE TABLE #C (C_ID INT)
INSERT INTO #B(B_ID) VALUES
(10),
(20),
(30),
(40)
INSERT INTO #C(C_ID)VALUES
(1),
(2),
(3),
(4)
CREATE TABLE #A
(
B_ID INT
, C_ID INT
, RndVal INT
)
INSERT INTO #A(B_ID, C_ID, RndVal)
SELECT
#B.B_ID
, #C.C_ID
, 0
FROM #B CROSS JOIN #C;
Then I'm attempting to add the random column using the following. The logic is to add random numbers between 1 and 16 > then to effectively overwrite any that are duplicated with other numbers > in a loop ...
SELECT
ROW_NUMBER() OVER(ORDER BY B_ID) AS Row
, B_ID
, C_ID
, RndVal
INTO #myTable
FROM #A
DECLARE #rowsRequired INT = (SELECT COUNT(*) CNT FROM #myTable)
DECLARE #i INT = (SELECT #rowsRequired - SUM(CASE WHEN RndVal > 0 THEN 1 ELSE 0 END) FROM #myTable)--0
DECLARE #end INT = 1
WHILE #end > 0
BEGIN
SELECT #i = #rowsRequired - SUM(CASE WHEN RndVal > 0 THEN 1 ELSE 0 END) FROM #myTable
WHILE #i>0
BEGIN
UPDATE x
SET x.RndVal = FLOOR(RAND()*#rowsRequired)
FROM #myTable x
WHERE x.RndVal = 0
SET #i = #i-1
END
--this is to remove possible duplicates
UPDATE c
SET c.RndVal = 0
FROM
#myTable c
INNER JOIN
(
SELECT RndVal
FROM #myTable
GROUP BY RndVal
HAVING COUNT(RndVal)>1
) t
ON
c.RndVal = t.RndVal
SET #end = ##ROWCOUNT
END
TRUNCATE TABLE #A
INSERT INTO #A
SELECT
B_ID
, C_ID
, RndVal
FROM #myTable
If the original table has 6 rows then the result should end up something like this
B_ID|C_ID|RndVal
----------------
| | 5
| | 4
| | 1
| | 6
| | 3
| | 2
I don't understand your code, frankly
This will update each row with a random number, non-repeated number between 1 and the number of rows in the table
UPDATE T
SET SomeCol = T2.X
FROM
MyTable T
JOIN
(
SELECT
KeyCol, ROW_NUMBER() OVER (ORDER BY NEWID()) AS X
FROM
MyTable
) T2 ON T.KeyCol = T2.KeyCol
This is more concise but can't test to see if it works as expected
UPDATE T
SET SomeCol = X
FROM
(
SELECT
SomeCol, ROW_NUMBER() OVER (ORDER BY NEWID()) AS X
FROM
MyTable
) T
When you add TOP (1) (because you need to update first RndVal=0 record) and +1 (because otherwise your zero mark means nothing) to your update, things will start to move. But extremely slowly (around 40 seconds on my rather outdated laptop). This is because, as #myTable gets filled with generated random numbers, it becomes less and less probable to get missing numbers - you usually get duplicate, and have to start again.
UPDATE top (1) x
SET x.RndVal = FLOOR(RAND()*#rowsRequired) + 1
FROM #myTable x
WHERE x.RndVal = 0
Of course, #gbn has perfectly valid solution.
This is basically the same as the previous answer, but specific to your code:
;WITH CTE As
(
SELECT B_ID, C_ID, RndVal,
ROW_NUMBER() OVER(ORDER BY NewID()) As NewOrder
FROM #A
)
UPDATE CTE
SET RndVal = NewOrder
SELECT * FROM #A ORDER BY RndVal