SQL sequence updating column in reverse order - sql

I'm trying to update a column cohort_number in a table with sequential values from 1 to x (in this case 42) using a seq as below.
CREATE SEQUENCE seq start with 1 increment by 1 no maxvalue no cycle
UPDATE t1
SET cohort_number = next value for seq, instance_number = x.instanceNumber
FROM
(
SELECT id,
1 instanceNumber
FROM t1
) x
DROP SEQUENCE seq
However on update rather than the first row cohort_number = 1, second row = 2 and so on, the first row cohort_column = 42, second row cohort_column = 2. I.e it appears that the update is being processed from the last entry in the select result rather than the first. Is there anyway around this?
I've also tried with ROW_NUMBER as below, but every value for the cohort_column is set to 1, which I believe is due to id having no duplicate values (but I'm guessing here)
UPDATE t1
SET cohort_number = x.cohort_number, instance_number = x.instance_number
FROM
(
SELECT id,
ROW_NUMBER() over (order by id) as cohort_number,
1 instance_number
FROM t1
) x

The strange and proprietary UPDATE ... FROM syntax makes my head hurt.
This:
UPDATE t1
SET cohort_number = x.cohort_number, instance_number = x.instance_number
FROM
(
SELECT id,
ROW_NUMBER() over (order by id) as cohort_number,
1 instance_number
FROM t1
) x
Doesn't work, because you're updating T1, without correlating it with x, and your're not updating x. Either would work.
I find it much easier to write a SELECT query that returns all the rows that will be updated, along with the new values for columns to be updated. Then update that:
with x as
(
SELECT id,
cohort_number
instance_number,
ROW_NUMBER() over (order by id) as new_cohort_number,
1 new_instance_number
FROM t1
)
update x set cohort_number = new_cohort_number, instance_number = new_instance_number

Why would you use a sequence for this? Just use row_number():
UPDATE toupdate
SET cohort_number = seqnum,
instance_number = new_instanceNumber
FROM (SELECT t1.*, ROW_NUMBER() OVER (ORDER BY id DESC) as seqnum
1 as new_instanceNumber
FROM t1
) toupdate;

Related

Insert values for whole column in SQL Server

Is there any way to insert different values for specific column, not whole row in SQL Server.
Classic UPDATE SET would set all to same value.
For example I want to set some int values to Ranking column for each of 3 rows, without dropping them and doing complete new insert into.
Use row_number()
update a set ranking =rn from tablename a join
(select id,name, row_number() over(order by id) as rn
from tablename) b on a.id=b.id
do update
update tabale
set ranking= your_va
with cte as
(
select * ,row_number() over(order by id) rn
) update cte set ranking=rn where id<=3
What value do you want to set ranking to?
Just any value:
update mytable set ranking = id;
Certain values:
update mytable set ranking =
case name
when 'Positive' then 1
when 'Neutral' then 2
when 'Negative' then 3
else 4
end;

Oracle: UPDATE with ORDER BY [duplicate]

I want to populate a table column with a running integer number, so I'm thinking of using ROWNUM. However, I need to populate it based on the order of other columns, something like ORDER BY column1, column2. That is, unfortunately, not possible since Oracle does not accept the following statement:
UPDATE table_a SET sequence_column = rownum ORDER BY column1, column2;
Nor the following statement (an attempt to use WITH clause):
WITH tmp AS (SELECT * FROM table_a ORDER BY column1, column2)
UPDATE tmp SET sequence_column = rownum;
So how do I do it using an SQL statement and without resorting to cursor iteration method in PL/SQL?
This should work (works for me)
update table_a outer
set sequence_column = (
select rnum from (
-- evaluate row_number() for all rows ordered by your columns
-- BEFORE updating those values into table_a
select id, row_number() over (order by column1, column2) rnum
from table_a) inner
-- join on the primary key to be sure you'll only get one value
-- for rnum
where inner.id = outer.id);
OR you use the MERGE statement. Something like this.
merge into table_a u
using (
select id, row_number() over (order by column1, column2) rnum
from table_a
) s
on (u.id = s.id)
when matched then update set u.sequence_column = s.rnum
UPDATE table_a
SET sequence_column = (select rn
from (
select rowid,
row_number() over (order by col1, col2)
from table_a
) x
where x.rowid = table_a.rowid)
But that won't be very fast and as Damien pointed out, you have to re-run this statement each time you change data in that table.
First Create a sequence :
CREATE SEQUENCE SEQ_SLNO
START WITH 1
MAXVALUE 999999999999999999999999999
MINVALUE 1
NOCYCLE
NOCACHE
NOORDER;
after that Update the table using the sequence:
UPDATE table_name
SET colun_name = SEQ_SLNO.NEXTVAL;
A small correction just add AS RN :
UPDATE table_a
SET sequence_column = (select rn
from (
select rowid,
row_number() over (order by col1, col2) AS RN
from table_a
) x
where x.rowid = table_a.rowid)

Updating a column with the earliest date which has the same identifier, and has a column > 0

I have a database which, simiplified, is as follows :
ID | SecondID | DateRecorded | NumberToCheck | NumberToUpdate
NumberToUpdate currently has a value for 0 for all rows.
I wish to update NumberToUpdate with the value for NumberToCheck on the same row, MINUS the value for NumberToCheck which has the earliest DateRecorded "(Min(DateRecorded)" where NumberToCheck is greater than 0, and which has the same ID and secondID as the original row.
So far I have
UPDATE dbo.Table
SET NumberToUpdate =//Update NumberToUpdate
NumberToCheck - //NumberToCheck from the current row, subtracting...
(SELECT TOP 1 t2.NumberToCheck FROM Table t2 WHERE ID = t2.ID AND secondID = t2.secondID AND t2.DateRecorded =
(SELECT TOP 1 MIN(t3.DateRecorded) FROM Table t3 WHERE t2.ID = t3.ID AND t2.secondID = t3.secondID AND t3.Passes > 0))
//the NumberToCheck with the earliest date, of the same ID.
This is not correct however, and is returning me values which make no sense (including minus values of which there shouldn't be any!)
What have I forgotten here?
Thanks very much
First, you should start with a select query to get the value you want:
select t.*
from (select t.*, row_number() over (partition by id order by date) as seqnum
from table t
where number_to_check > 0
) t
where seqnum = 1
Now, you can use this in your original update:
with vals as (select t.*
from (select t.*, row_number() over (partition by id order by date) as seqnum
from table t
where NumberToCheck > 0
) t
where seqnum = 1
)
update table
set NumberToUpdate = NumberToCheck - vals.NumberToCheck
from vals
where t.id = vals.id
UPDATE dbo.Table as t1
INNER JOIN
(
SELECT MIN(DateRecord) as mindate, ID
FROM dbo.Table
GROUP BY ID
) as mindates
ON t1.ID = mindates.ID
INNER JOIN
dbo.Table as substractions
ON mindates.mindate = substraction.DateRecord
AND mindates.ID = substraction.ID
SET t1.numberToUpdate = t1.numberToCheck - substractions.NumberToCheck
WHERE substraction.NumberToCheck > 0
--your questions is ambigious here: did you mean this one should be greater than 0, or should t1.NumberToCheck > 0 ?
AND t1.DateRecord <> mindates.mindate
--Assuming that you don't want to update the record with the lowest date.
Note:
This assumes that DateRecord combined with ID is unique, which isn't guaranteed by your structure. I'm afraid that with this table layout, there is no other way.

Oracle: Updating a table column using ROWNUM in conjunction with ORDER BY clause

I want to populate a table column with a running integer number, so I'm thinking of using ROWNUM. However, I need to populate it based on the order of other columns, something like ORDER BY column1, column2. That is, unfortunately, not possible since Oracle does not accept the following statement:
UPDATE table_a SET sequence_column = rownum ORDER BY column1, column2;
Nor the following statement (an attempt to use WITH clause):
WITH tmp AS (SELECT * FROM table_a ORDER BY column1, column2)
UPDATE tmp SET sequence_column = rownum;
So how do I do it using an SQL statement and without resorting to cursor iteration method in PL/SQL?
This should work (works for me)
update table_a outer
set sequence_column = (
select rnum from (
-- evaluate row_number() for all rows ordered by your columns
-- BEFORE updating those values into table_a
select id, row_number() over (order by column1, column2) rnum
from table_a) inner
-- join on the primary key to be sure you'll only get one value
-- for rnum
where inner.id = outer.id);
OR you use the MERGE statement. Something like this.
merge into table_a u
using (
select id, row_number() over (order by column1, column2) rnum
from table_a
) s
on (u.id = s.id)
when matched then update set u.sequence_column = s.rnum
UPDATE table_a
SET sequence_column = (select rn
from (
select rowid,
row_number() over (order by col1, col2)
from table_a
) x
where x.rowid = table_a.rowid)
But that won't be very fast and as Damien pointed out, you have to re-run this statement each time you change data in that table.
First Create a sequence :
CREATE SEQUENCE SEQ_SLNO
START WITH 1
MAXVALUE 999999999999999999999999999
MINVALUE 1
NOCYCLE
NOCACHE
NOORDER;
after that Update the table using the sequence:
UPDATE table_name
SET colun_name = SEQ_SLNO.NEXTVAL;
A small correction just add AS RN :
UPDATE table_a
SET sequence_column = (select rn
from (
select rowid,
row_number() over (order by col1, col2) AS RN
from table_a
) x
where x.rowid = table_a.rowid)

Selecting a given row in a table

here is a simple problem. I have a table of 500 rows and what to be able to select a given row number n. This is what I am doing:
select *
from table
where table.arg1 ='A'
and time_stamp=to_date('1/8/2010','MM/DD/YYYY')
and rownum = n
But it would only work for the row 1, for the rest it doesn't return anything. Any idea?
The reason why where rownum = 3 returns an empty rowset is that the condition is not true for the first row. For the second row, there is still no first row in the resultset, and rownum is still 1. So the condition fails again. See this page for a more detailed explanation.
You can use row_number() in a subquery:
select *
from (
select row_number() over (order by col1) as rn, yt.*
from YourTable yt
) sub
where rn = 3
Or even simpler, but perhaps more confusing, using rownum itself:
select *
from (
select rownum as rn, yt.*
from YourTable yt
) sub
where rn = 3