UPDATE statement to generate row number [duplicate] - sql

This question already has answers here:
Oracle: Updating a table column using ROWNUM in conjunction with ORDER BY clause
(4 answers)
Closed 8 years ago.
Oracle 10g
I have a table that has a compound key, which I want to replace with a singular key. So I've added an id column. Now I need a single update statement update existing data.
Example:
MyTable(NewID,CMP_Key1,CMP_Key2)
NULL,1,1
NULL,1,2
NULL,2,2
NULL,2,2
Needs to be updated to:
1,1,1
2,1,2
3,2,2
4,2,2
What I've tried so far:
Update MyTable SET NewID = (SELECT ROWNUM FROM DUAL);
Which doesn't work. This will set them all to 1.

You can just do:
update MyTable set NewId = rownum;
SQL Fiddle.
But presumably you'll want to increment the NewId column for future inserts, quite likely with a sequence and maybe a trigger. You'd need to make the sequence start with the highest value you set manually (i.e. the number of rows in the table when you run the update), so you might as well just use the sequence here:
create sequence MyTableSeq;
update MyTable set NewId = MyTableSeq.nextval;
SQL Fiddle.
Both assume this is a purely synthetic key and you don't want to impose any ordering as it's generated.

Try this one
merge into mytable t
using (select t.rowid rid, t.rownum id from mytable t) s
on (t.rowid = s.rid)
when matched then update set
t.newid= s.id;
commit;

Related

Alter / Update PostgreSQL Sequence

How can I update the last_value field in my sequence and add 1 to it?
The query I tried: ALTER SEQUENCE "seq_hours" SET 'last_value' = 'last_value' + 1
However this did not work.
Use setval() with a subquery to get the value from a table, e.g.
SELECT setval('seq_hours', (SELECT max(last_value)+1 FROM t));
EDIT: This solution only makes sense if you want to set the current value of a sequence based on a value from a given table. If you only want the next possible value of a sequence you should use nextval as #a_horse_with_no_name suggested (see comments)

postgresql: Fast way to update the latest inserted row

What is the best way to modify the latest added row without using a temporary table.
E.g. the table structure is
id | text | date
My current approach would be an insert with the postgresql specific command "returning id" so that I can update the table afterwards with
update myTable set date='2013-11-11' where id = lastRow
However I have the feeling that postgresql is not simply using the last row but is iterating through millions of entries until "id = lastRow" is found. How can i directly access the last added row?
update myTable date='2013-11-11' where id IN(
SELECT max(id) FROM myTable
)
Just to add to mvb13's answer (since I don't have enough points to comment directly yet) there is one word missing. Hopefully, this will save someone some time from working out the correct syntax LOL.
update myTable set date='2013-11-11' where id IN(
SELECT max(id) FROM myTable
);

SQLite UPSERT with 2 constraints [duplicate]

This question already has answers here:
SQLite INSERT - ON DUPLICATE KEY UPDATE (UPSERT)
(5 answers)
SQL: How to update or insert if doesn't exist?
(2 answers)
Closed 9 years ago.
I have an sql table with 3 columns, none of which is UNIQUE ( but the pair name + role is ):
Name | Role | Votes
What I need to do is, write an sqllite query that stick to the following rules :
If a row with the given name and role already exist, votes is
incremented by 1
If not, a new row is created with Votes = 1
I've looked into INSERT OR REPLACE and this great post but it doesn't seem to help me that much, and I'm not even sure INSERT OR REPLACE is a viable option, since something like
INSERT OR REPLACE INTO words (name,role,votes)
VALUES ('foo','bar', coalesce((
select votes from words where name = 'foo' and role='bar'),0)+1)
always insterts and never replace
You simply need to create unique index over your 2 columns for this to work:
CREATE UNIQUE INDEX words_name_role_idx ON words (name,role)
Note that you do not create unique index for any single column, but for combination of 2 as a whole.
After that, your REPLACE INTO statement should start working correctly:
REPLACE INTO words (name,role,votes) VALUES ('foo','bar',
coalesce((
SELECT votes FROM words
WHERE name = 'foo' AND role='bar'),0
)+1
)
(note that I have changed counter to votes above).
This query will update your record with +1.
update todo set text='raj',complete='raj',pk=((SELECT pk FROM todo where text='raj' and complete='raj')+1) where (SELECT pk FROM todo where text='raj' and complete='raj')
EDIT YOUE QUERY
update words set name='foo',role='bar', votes =((SELECT votes FROM words where name='foo' and role='bar')+1) where (SELECT votes FROM words where name='foo' and role='bar')
And make insert query if this condition will not true.

Getting Identity Column Value [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to get the primary key of the last row inserted into the table
In SQL Server 2008, I have a stored proc that inserts in a table which includes identity column for ID. I need to return the ID of record to my application so that I can use it for related tables.
How can I get generated ID by SQL?
Use select Scope_Identity() to get the ID
A separate SQL statement
SELECT SCOPE_IDENTITY()
Or the OUTPUT clause
INSERT MyTable (...=
OUTPUT INSERTED.KeyCol
VALUES (...) --Or SELECT ... FROM Another table)
There are multiple options that are a bit different:
SCOPE_IDENTITY() - that's what I would use
IDENT_CURRENT( 'table_name' )
##IDENTITY

MySQL -- mark all but 1 matching row

This is similar to this question, but it seems like some of the answers there aren't quite compatible with MySQL (or I'm not doing it right), and I'm having a heck of a time figuring out the changes I need. Apparently my SQL is rustier than I thought it was. I'm also looking to change a column value rather than delete, but I think at least that part is simple...
I have a table like:
rowid SERIAL
fingerprint TEXT
duplicate BOOLEAN
contents TEXT
created_date DATETIME
I want to set duplicate=true for all but the first (by created_date) of each group by fingerprint. It's easy to mark all of the rows with duplicate fingerprints as dupes. The part I'm getting stuck on is keeping the first.
One of the apps that populates the table does bulk loads of data, with multiple workers loading data from different sources, and the workers' data isn't necessarily partitioned by date, so it's a pain to try to mark these all as they come in (the first one inserted isn't necessarily the first one by date). Also, I already have a bunch of data in there I'll need to clean up either way. So I'd rather just have a relatively efficient query I can run after a bulk load to clean up than try to build it into that app.
Thanks!
MySQL needs to be explicitly told if the data you are grouping by is larger than 1024 bytes (see this link for details). So if your data in the fingerprint column is larger than 1024 bytes you should use set the max_sort_length variable (see this link for details about values allowed, and this link about how to set it) to a larger number so that the group by wont silently use only part of your data for grouping.
Once you're certain that MySQL will group your data properly, the following query will set the duplicate flag so that the first fingerprint record has duplicate set to FALSE/0 and any subsequent fingerprint records have duplicate set to TRUE/1:
UPDATE mytable m1
INNER JOIN (SELECT fingerprint
, MIN(rowid) AS minrow
FROM mytable m2
GROUP BY fingerprint) m3
ON m1.fingerprint = m3.fingerprint
SET m1.duplicate = m3.minrow != m1.rowid;
Please keep in mind that this solution does not take NULLs into account and if it is possible for the fingerprint field to be NULL then you would need additional logic to handle that case.
How about a two-step approach, assuming you can go offline during a data load:
Mark every item as duplicate.
Select the earliest row from each group, and clear the duplicate flag.
Not elegant, but gets the job done.
Here's a funny way to do it:
SET #rowid := 0;
UPDATE mytable
SET duplicate = (rowid = #rowid),
rowid = (#rowid:=rowid)
ORDER BY rowid, created_date;
First set a user variable to zero, assuming this is less than any rowid in your table.
Then use the MySQL UPDATE...ORDER BY feature to ensure that the rows are updated in order by rowid, then by created_date.
For each row, if the current rowid is not equal to the user variable #rowid, set duplicate to 0 (false). This will be true only on the first row encountered with a given value for rowid.
Then add a dummy set of rowid to its own value, setting #rowid to that value as a side effect.
As you UPDATE the next row, if it's a duplicate of the previous row, rowid will be equal to the user variable #rowid, and therefore duplicate will be set to 1 (true).
Edit: Now I have tested this, and I corrected a mistake in the line that sets duplicate.
Here's another way to do it, using MySQL's multi-table UPDATE syntax:
UPDATE mytable m1
JOIN mytable m2 ON (m1.rowid = m2.rowid AND m1.created_date < m2.created_date)
SET m2.duplicate = 1;
I don't know the MySQL syntax, but in PLSQL you just do:
UPDATE t1
SET duplicate = 1
FROM MyTable t1
WHERE rowid != (
SELECT TOP 1 rowid FROM MyTable t2
WHERE t2.fingerprint = t1.fingerprint ORDER BY created_date DESC
)
That may have some syntax errors, as I'm just typing off the cuff/not able to test it, but that's the gist of it.
MySQL version (not tested):
UPDATE t1
SET duplicate = 1
FROM MyTable t1
WHERE rowid != (
SELECT rowid FROM MyTable t2
WHERE t2.fingerprint = t1.fingerprint
ORDER BY created_date DESC
LIMIT 1
)
Untested...
UPDATE TheAnonymousTable
SET duplicate = TRUE
WHERE rowid NOT IN
(SELECT rowid
FROM (SELECT MIN(created_date) AS created_date, fingerprint
FROM TheAnonymousTable
GROUP BY fingerprint
) AS M,
TheAnonymousTable AS T
WHERE M.created_date = T.created_date
AND M.fingerprint = T.fingerprint
);
The logic is that the innermost query returns the earliest created_date for each distinct fingerprint as table alias M. The middle query determines the rowid value for each of those rows; it is a nuisance to have to do this (but necessary), and the code assumes that you won't get two records for the same fingerprint and timestamp. This gives you the rowid for the earlist record for each separate fingerprint. Then the outer query (the UPDATE) sets the 'duplicate' flag on all those rows where the rowid is not one of the earliest rows.
Some DBMS may be unhappy about doing (nested) sub-queries on the table being updated.