How to update a column of a table to a scaling value - sql

I'm trying to update a column in my table to use the values 1 through (a max number decided by a count of records).
I don't know if I'm explaining this right, so I set up a SQLFiddle with the data I'm trying to update.
SQL FIDDLE
I want to set the Version column to 1 through (the max number).
Is there some way to rewrite this query to a scale the Version number?
As in, I want the first record to use 1, the second record to use 2, and so on...
UPDATE Documents
SET Version = 1

You can do it with a CTE and no joins:
with RankedDocument as
(
select *
, rn = row_number() over (order by ID)
from Documents
)
update RankedDocument
set Version = rn
SQL Fiddle with demo.

From what I can tell, you want every record from Documents to have a version number which is a number moving from 1 ..... N.
You could use a temporary table and ROW_NUMBER technique to get the incremental version and then UPDATE it back to your original table.
CREATE TABLE #Temp (ID int, Version int)
INSERT INTO #Temp (ID, Version)
SELECT ID, ROW_NUMBER() OVER (ORDER BY ID ASC)
FROM Documents
UPDATE Doc
SET Version = TT.Version
FROM Documents AS Doc INNER JOIN #Temp AS TT ON Doc.ID = TT.ID
DROP TABLE #Temp
If I understand you correctly..

Try this:
;WITH list AS (
SELECT
ID
, Version = ROW_NUMBER() OVER( ORDER BY VersionID ASC )
FROM Documents
)
UPDATE d SET
d.Version = x.Version
FROM Documents AS d
INNER JOIN list as x ON d.ID=x.ID
SELECT * FROM Documents
You can change the order ( ORDER BY VersionID ASC )
to the one you need.

Related

Updating records in batches in Rails/Postgres to reduce UPDATE calls to the database? [duplicate]

I have a table called 'cards', which has a column called 'position'
How can I update/set the 'position' to equal the row number of each record, using ROW_NUMBER()?
I am able to query the records and get the correct values using this statement:
"SELECT *, ROW_NUMBER() OVER () as position FROM cards"
So, I would like to do this but have it update the new values in the database.
Let me assume that cards has a primary key. Then you can use join:
update cards c
set position = c2.seqnum
from (select c2.*, row_number() over () as seqnum
from cards c2
) c2
where c2.pkid = c.pkid;
I should note that the over () looks strange but Postgres does allow it. Normally an order by clause would be included.
Original question was tagged with SQLite.
Starting from SQLite 3.25.0 we could natively use ROW_NUMBER.
CREATE TABLE cards(pk INT PRIMARY KEY, c VARCHAR(2), seq INT);
INSERT INTO cards(pk, c) VALUES (10,'2♥'),(20,'3♥'),(30, '4♥');
WITH cte AS (SELECT *, ROW_NUMBER() OVER() AS rn FROM cards)
UPDATE cards SET seq = (SELECT rn FROM cte WHERE cte.pk = cards.pk);
SELECT * FROM cards;
Exactly the same code will work with PostgreSQL too: Rextester Demo

Update table based on the condition

I need to update the staging table based on the type if ZMD2 is present then update the records else update PNTP records.
UPDATE ITEMS_STAGING SET TYPE=b.TYPE,VALUE=b.VALUE
FROM ITEMS_STAGING a,ITEMS b
WHERE a.PARENT=b.PARENT
In the above statement I need to pick only ZMD2 records for the same parent if exists if not PNTP records. I tried to do UNION for the ITEMS it dint help.
Staging table Output:
Kindly help.
Thanks
You need to use analytical function row_number which will group the rows by parent column to give them numbers and then we will take only one record from each group to update staging table using merge statement as following:
MERGE INTO ITEM_STAGING M
USING (
SELECT T.*,
ROW_NUMBER() OVER(PARTITION BY T.PARENT ORDER BY T.TYPE DESC) RN
FROM ITEMS T
)
ON (M.PARENT = T.PARENT AND T.RN = 1)
WHEN MATCHED THEN
UPDATE SET M.TYPE = T.TYPE AND M.VALUE = T.VALUE;
Cheers!!
You may try below query -
SELECT *
FROM (SELECT IS.*, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY TYPE DESC) RN
FROM ITEMS_STAGING)
WHERE RN = 1;
I am not sure what you want to update in this table.

How can I insert a new column into the database which has the label ‘1’/’2’/’3’/’4’ # based upon the quantile of another column?

I am having an issue with inserting a column in the table. I already calculated quantile of the one of the column but how I a going to insert into a table?
.open books.db
ALTER TABLE booksCSV ADD COLUMN quantile_rank;
SELECT average_rating, NTILE(4) OVER (ORDER BY average_rating DESC) AS quantile_rank FROM booksCSV;
I actually don't recommend doing this, because if the column you have in mind is just easily derived from the underlying table data, then it is best to not store it. That being said, you might just be looking for an update here:
ALTER TABLE booksCSV ADD quantile_rank REAL;
UPDATE booksCSV b
SET quantile_rank = (SELECT t.quartile_rank
FROM (
SELECT id, NTILE(4) OVER (ORDER BY average_rating DESC) AS quartile_rank
FROM booksCSV
) t
WHERE t.id = b.id);
After adding the column, you can use a CTE as follows:
WITH cte as (SELECT rowid, NTILE(4) OVER (ORDER BY average_rating DESC) AS qr FROM booksCSV)
UPDATE booksCSV
SET quantile_rank = (SELECT qr FROM cte
WHERE booksCSV.rowid = rowid);

Update with Where, Order by and Limit does not work

I am using SQLite 3.
When I input the following query
UPDATE MyTable Set Flag = 1 WHERE ID = 5 Order By OrderID DESC LIMIT 1;
I will always get an error:
near Order By, syntax error
I cannot figure out what is the problem with my query
To use LIMIT and ORDER BY in an UPDATE or DELETE statement, you have to do two things:
Build a custom version of the sqlite3.c amalgamation from source, configuring it with the --enable-update-limit option.
Compile that custom sqlite3.c into your project with SQLITE_ENABLE_UPDATE_DELETE_LIMIT defined to 1.
"Order By OrderID DESC LIMIT 1" is for selecting top one ordered result
so you should use it in select query.
you should do a subquery where you first get the id and then update it:
UPDATE MyTable
SET Flag = 1
WHERE (ID,OrderID) IN (SELECT ID,OrderID
FROM MyTable
WHERE ID = 5
ORDER BY OrderID DESC LIMIT 1);
Demo
You could use ROWID:
UPDATE MyTable
SET Flag = 1
WHERE ROWID IN (SELECT ROWID FROM MyTable WHERE ID = 5
ORDER BY OrderID DESC LIMIT 1);
db<>fiddle demo
or (ID,OrderID) tuple:
UPDATE MyTable
SET Flag = 1
WHERE (ID, ORDERID) IN (SELECT ID, ORDERID FROM MyTable WHERE ID = 5
ORDER BY OrderID DESC LIMIT 1);
db<>fiddle demo2
And if you need to do it in bulk for every ID(SQLite 3.25.0):
WITH cte AS (
SELECT *,ROW_NUMBER() OVER(PARTITION BY ID ORDER BY OrderID DESC) AS rn FROM tab
)
UPDATE tab
SET Flag = 1
WHERE (ID, OrderID) IN (
SELECT ID, OrderID
FROM cte
WHERE rn = 1
);
Order By statement will not work in update query.
You have to use alternate way
UPDATE MyTable Set Flag = 1 WHERE ID = 5
and OrderId = (select max(OrderId) from MyTable where Id = 5);
If you have used the query like above it will work.
Introduction
Below I'm presenting two solutions to solve the issue and perform a proper UPDATE. At the end of each solution there's a live example on sample data included.
First does not require you to input any id and works for the entire table by picking the latest orderid for each id and changing it's flag to 1
Second requires you to input an id and works only for updating one id on the run
I'd personally go with first solution, but I am not sure about your requirement, thus posting two possibilities.
First solution - update entire table
Explanation here, for code scroll down.
For this we will use Row Value construction (id, orderid) just like for the second solution.
It will find the latest row based on orderid and update only that row for given (id, orderid) pair. More on that is included in Explanation of second solution.
We will also need to simulate row_number function to assign each row ranking numbers, to find out which row has the latest orderid for every id and mark then as 1 to be able to pull only those for update. This will allow us to update multiple rows for different ids in one statement. SQLite will have this functionality built in version 3.2.5 but for now, we will work with a subquery.
To generate row numbers we will use this:
select
*,
(select count(*) from mytable m1 where m1.id = m2.id and m1.orderid >= m2.orderid) as rn
from mytable m2
Then we just need to filter the output on rn = 1 and we have what we need.
That said, the whole UPDATE statement will look like:
Code
update mytable
set flag = 1
where (id,orderid) in (
select id, orderid
from (
select *, (select count(*) from mytable m1 where m1.id = m2.id and m1.orderid >= m2.orderid) as rn
from mytable m2
) m
where
m.rn = 1
and m.id = mytable.id
);
Live DEMO
Here's db fiddle to see this solution live on sample data.
Second solution - update only one ID
If you know your ID to be updated and want to run UPDATE statement for only one id, then this will work:
Code
update mytable
set flag = 1
where (id,orderid) in (
select id, orderid
from mytable
where id = 5
order by orderid desc
limit 1
);
Explanation
(id, orderid) is a construction called Row Value for which SQLite compares scalar values from left to right.
Example taken from documentation:
SELECT (1,2,3) = (1,2,3) -- outputs: 1
Live DEMO
Here's db fiddle to see this solution live on sample data.
SQL
UPDATE MyTable
SET Flag = 1
WHERE ID = 5
AND OrderID IN (SELECT OrderID
FROM MyTable
WHERE ID = 5
ORDER BY OrderID DESC
LIMIT 1);
Demo
SQLFiddle demo: http://sqlfiddle.com/#!5/6d596/2

SQL Select highest values from table on two (or more) columns

not sure if there's an elegant way to acheive this:
Data
ID Ver recID (loads more columns of stuff)
1 1 1
2 2 1
3 3 1
4 1 2
5 1 3
6 2 3
So, we have ID as the Primary Key, the Ver as the version and recID as a record ID (an arbitary base ID to tie all the versions together).
So I'd like to select from the following data, rows 3, 4 and 6. i.e. the highest version for a given record ID.
Is there a way to do this with one SQL query? Or would I need to do a SELECT DISTINCT on the record ID, then a seperate query to get the highest value? Or pull the lot into the application and filter from there?
A GROUP BY would be sufficient to get each maximum version for every recID.
SELECT Ver = MAX(Ver), recID
FROM YourTable
GROUP BY
recID
If you also need the corresponding ID, you can wrap this into a subselect
SELECT yt.*
FROM Yourtable yt
INNER JOIN (
SELECT Ver = MAX(Ver), recID
FROM YourTable
GROUP BY
recID
) ytm ON ytm.Ver = yt.Ver AND ytm.recID = yt.RecID
or, depending on the SQL Server version you are using, use ROW_NUMBER
SELECT *
FROM (
SELECT ID, Ver, recID
, rn = ROW_NUMBER() OVER (PARTITION BY recID ORDER BY Ver DESC)
FROM YourTable
) yt
WHERE yt.rn = 1
Getting maximum ver for a given recID is easy. To get the ID, you need to join on a nested query that gets these maximums:
select ID, ver, recID from table x
inner join
(select max(ver) as ver, recID
from table
group by recID) y
on x.ver = y.ver and x.recID = y.recID
You could use a cte with ROW_NUMBER function:
WITH cte AS(
SELECT ID, Ver, recID
, ROW_NUMBER()OVER(PARTITION BY recID ORDER BY Ver DESC)as RowNum
FROM data
)
SELECT ID,Ver,recID FROM cte
WHERE RowNum = 1
straighforward example using a subquery:
SELECT a.*
FROM tab a
WHERE ver = (
SELECT max(ver)
FROM tab b
WHERE b.recId = a.recId
)
(Note: this assumes that the combination of (recId, ver) is unique. Typically there would be a primary key or unique constraint on those columns, in that order, and then that index can be used to optimize this query)
This works on almost all RDBMS-es, although the correlated subquery might not be handled very efficiently (depending on RDBMS). SHould work fine in MS SQL 2008 though.