Im trying to update a field in an oracle table, but I would only like to update 75 rows based on the order by creationdate field ascending.
This is what I have so far, but its not working.
UPDATE extractcandidate
SET process = 15
WHERE process IN
(Select process from extractcandidate where process = 1500 and rownum <=75 order by creationdate);
As #Gordon mentioned, you need to do the ORDER BY before the ROWNUM.
Firstly, order by creationdate:
SELECT *
FROM extractcandidate
WHERE process=1500
ORDER BY creationdate;
Secondly, limit the number to 75:
SELECT *
FROM (
SELECT *
FROM extractcandidate
WHERE process=1500
ORDER BY creationdate
)
WHERE rownum <= 75;
Now you can feed it into the UPDATE. To find the correct rows, you would normally use a primary key column. This seems to be missing in your case, so you can fall back to Oracle's internal ROWID:
UPDATE extractcandidate
SET process=15
WHERE rowid IN (
SELECT ri
FROM (
SELECT rowid as ri
FROM extractcandidate
WHERE process=1500
ORDER BY creationdate
)
WHERE rownum <= 75
);
You need an additional subquery for your method to work:
UPDATE extractcandidate
SET process = 15
WHERE ec.process = 1500 AND
creationdate IN (SELECT ec.creationdate
FROM (SELECT ec.*
FROM extractcandidate ec
WHERE ec.process = 1500
ORDER BY ec.creationdate
)
WHERE rownum <= 75
);
Notes:
You need to do the sorting before using rownum.
The comparison needs to be on creation date, not process.
Related
I am trying to delete 41,6% of my old rows from my oracle data table ( senstrig is a date format):
DELETE FROM
(WITH RS AS (SELECT * FROM OLD_WIFISIGN WHERE SENSID= 1 ORDER BY SENSTRIG ASC))
WHERE ROWNUM <= (SELECT COUNT (*)/ 2.4 FROM RS);
But it returns an error:
ORA-00928 missing SELECT
I have already tried several versions but with no luck.
Could you please help me how can I make this "delete from" runnable?
Test table, 1000 rows, all with sensid = 1:
create table old_wifisign (sensid, senstrig) as (
select 1, trunc(sysdate) - level
from dual connect by level <= 1000);
Delete:
delete
from old_wifisign
where rowid in (
select rowid
from (
select rowid, row_number() over (order by senstrig) / count(1) over () rto
from old_wifisign
where sensid = 1 )
where rto <= .416)
Result: 416 rows with oldest senstrig deleted. Note that only sensid 1 is taken into calculations here, as in your query.
To delete 41,6% of old rows check fist the boundary date to delete and than use it.
The analytic function PERCENT_RANK gives you the youngest senstrig you do not want to delete.
with perc_rank as (
select SENSID, SENSTRIG,
PERCENT_RANK() OVER (ORDER BY senstrig) AS pr
from old_wifisign)
select max(SENSTRIG) from perc_rank
where pr < .416
Than you simple takes this date and performs a DELETE
delete from old_wifisign
where SENSTRIG <
(with perc_rank as (
select SENSID, SENSTRIG,
PERCENT_RANK() OVER (ORDER BY senstrig) AS pr
from old_wifisign)
select max(SENSTRIG) from perc_rank
where pr < .416
);
Anyway you should take soem care considering ties - thing about a case when half of the rows in the table have identical senstrig
Put WITH before DELETE:
WITH RS AS (SELECT * FROM OLD_WIFISIGN WHERE SENSID= 1 ORDER BY SENSTRIG ASC)
DELETE FROM OLD_WIFISIGN
WHERE ROWNUM <= (SELECT COUNT (*)/ 2.4 FROM RS);
Still a bit weird, what is the purpose of the order by?
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
This is my query, I plan to run it in batches of perhaps 5000 hence the rownum < 5000
delete my_table
where rownum < 5000
and type = 'Happy'
and id not in
( select max_id
from ( select max(log_id) max_id
, object_id
, type
from my_table
where type = 'Happy'
group
by id
, type
)
)
I want to delete happy records but keeping the maximum log id, per object id
I hope that makes sense.
Should I be using some sort of join to improve performance?
I think this might run faster as a correlated subquery:
Delete
from my_table
where type = 'Happy' and
exists (select 1
from my_table t2
where t2.object_id = my_table.object_id and
t2.type = my_table.type and
t2.id > my_table.id
);
Then, an index on my_table(object_id, type, id) might also help this query.
Since you only care to delete ANY 5000 log entries for type = 'Happy', as long as its not the most recent for any object_id, then you can do something like this:
delete
from my_table
where log_id in (
select log_id from (
select log_id,
row_number() over (partition by object_id order by log_id desc) rnk
from my_table
where typ = 'Happy'
and rownum <= 5000
)
where rnk > 1
)
This is different from what you have because in your approach, you still need to calculate the max(id) per object across the entire table, which isn't necessary (and log tables can get very large). You just need to make sure you're not deleting the "newest" row (per object) of the 5000 batch rows. Personally, I prefer to setup log tables using partitions, but not everyone has this option.
Hope that helps.
You could simplify the query to:
delete my_table
where rownum < 5000
and type = 'Happy'
and id not in (select max(log_id) max_id
from my_table
where type = 'Happy'
group by object_id, type)
This question already has answers here:
Implement paging (skip / take) functionality with this query
(6 answers)
Closed 1 year ago.
I have this query with MySQL:
select * from table1 LIMIT 10,20
How can I do this with SQL Server?
Starting SQL SERVER 2005, you can do this...
USE AdventureWorks;
GO
WITH OrderedOrders AS
(
SELECT SalesOrderID, OrderDate,
ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
FROM Sales.SalesOrderHeader
)
SELECT *
FROM OrderedOrders
WHERE RowNumber BETWEEN 10 AND 20;
or something like this for 2000 and below versions...
SELECT TOP 10 * FROM (SELECT TOP 20 FROM Table ORDER BY Id) ORDER BY Id DESC
Starting with SQL SERVER 2012, you can use the OFFSET FETCH Clause:
USE AdventureWorks;
GO
SELECT SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader
ORDER BY SalesOrderID
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY;
GO
http://msdn.microsoft.com/en-us/library/ms188385(v=sql.110).aspx
This may not work correctly when the order by is not unique.
If the query is modified to ORDER BY OrderDate, the result set returned is not as expected.
This is how I limit the results in MS SQL Server 2012:
SELECT *
FROM table1
ORDER BY columnName
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY
NOTE: OFFSET can only be used with or in tandem to ORDER BY.
To explain the code line OFFSET xx ROWS FETCH NEXT yy ROW ONLY
The xx is the record/row number you want to start pulling from in the table, i.e: If there are 40 records in table 1, the code above will start pulling from row 10.
The yy is the number of records/rows you want to pull from the table.
To build on the previous example: If table 1 has 40 records and you began pulling from row 10 and grab the NEXT set of 10 (yy).
That would mean, the code above will pull the records from table 1 starting at row 10 and ending at 20. Thus pulling rows 10 - 20.
Check out the link for more info on OFFSET
This is almost a duplicate of a question I asked in October:
Emulate MySQL LIMIT clause in Microsoft SQL Server 2000
If you're using Microsoft SQL Server 2000, there is no good solution. Most people have to resort to capturing the result of the query in a temporary table with a IDENTITY primary key. Then query against the primary key column using a BETWEEN condition.
If you're using Microsoft SQL Server 2005 or later, you have a ROW_NUMBER() function, so you can get the same result but avoid the temporary table.
SELECT t1.*
FROM (
SELECT ROW_NUMBER OVER(ORDER BY id) AS row, t1.*
FROM ( ...original SQL query... ) t1
) t2
WHERE t2.row BETWEEN #offset+1 AND #offset+#count;
You can also write this as a common table expression as shown in #Leon Tayson's answer.
SELECT *
FROM (
SELECT TOP 20
t.*, ROW_NUMBER() OVER (ORDER BY field1) AS rn
FROM table1 t
ORDER BY
field1
) t
WHERE rn > 10
Syntactically MySQL LIMIT query is something like this:
SELECT * FROM table LIMIT OFFSET, ROW_COUNT
This can be translated into Microsoft SQL Server like
SELECT * FROM
(
SELECT TOP #{OFFSET+ROW_COUNT} *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum
FROM table
) a
WHERE rnum > OFFSET
Now your query select * from table1 LIMIT 10,20 will be like this:
SELECT * FROM
(
SELECT TOP 30 *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum
FROM table1
) a
WHERE rnum > 10
SELECT TOP 10 * FROM table;
Is the same as
SELECT * FROM table LIMIT 0,10;
Here's an article about implementing Limit in MsSQL Its a nice read, specially the comments.
This is one of the reasons I try to avoid using MS Server... but anyway. Sometimes you just don't have an option (yei! and I have to use an outdated version!!).
My suggestion is to create a virtual table:
From:
SELECT * FROM table
To:
CREATE VIEW v_table AS
SELECT ROW_NUMBER() OVER (ORDER BY table_key) AS row,* FROM table
Then just query:
SELECT * FROM v_table WHERE row BETWEEN 10 AND 20
If fields are added, or removed, "row" is updated automatically.
The main problem with this option is that ORDER BY is fixed. So if you want a different order, you would have to create another view.
UPDATE
There is another problem with this approach: if you try to filter your data, it won't work as expected. For example, if you do:
SELECT * FROM v_table WHERE field = 'test' AND row BETWEEN 10 AND 20
WHERE becomes limited to those data which are in the rows between 10 and 20 (instead of searching the whole dataset and limiting the output).
In SQL there's no LIMIT keyword exists. If you only need a limited number of rows you should use a TOP keyword which is similar to a LIMIT.
Must try. In below query, you can see group by, order by, Skip rows, and limit rows.
select emp_no , sum(salary_amount) from emp_salary
Group by emp_no
ORDER BY emp_no
OFFSET 5 ROWS -- Skip first 5
FETCH NEXT 10 ROWS ONLY; -- limit to retrieve next 10 row after skiping rows
Easy way
MYSQL:
SELECT 'filds' FROM 'table' WHERE 'where' LIMIT 'offset','per_page'
MSSQL:
SELECT 'filds' FROM 'table' WHERE 'where' ORDER BY 'any' OFFSET 'offset'
ROWS FETCH NEXT 'per_page' ROWS ONLY
ORDER BY is mandatory
This is a multi step approach that will work in SQL2000.
-- Create a temp table to hold the data
CREATE TABLE #foo(rowID int identity(1, 1), myOtherColumns)
INSERT INTO #foo (myColumns) SELECT myData order By MyCriteria
Select * FROM #foo where rowID > 10
SELECT
*
FROM
(
SELECT
top 20 -- ($a) number of records to show
*
FROM
(
SELECT
top 29 -- ($b) last record position
*
FROM
table -- replace this for table name (i.e. "Customer")
ORDER BY
2 ASC
) AS tbl1
ORDER BY
2 DESC
) AS tbl2
ORDER BY
2 ASC;
-- Examples:
-- Show 5 records from position 5:
-- $a = 5;
-- $b = (5 + 5) - 1
-- $b = 9;
-- Show 10 records from position 4:
-- $a = 10;
-- $b = (10 + 4) - 1
-- $b = 13;
-- To calculate $b:
-- $b = ($a + position) - 1
-- For the present exercise we need to:
-- Show 20 records from position 10:
-- $a = 20;
-- $b = (20 + 10) - 1
-- $b = 29;
If your ID is unique identifier type or your id in table is not sorted you must do like this below.
select * from
(select ROW_NUMBER() OVER (ORDER BY (select 0)) AS RowNumber,* from table1) a
where a.RowNumber between 2 and 5
The code will be
select * from limit 2,5
better use this in MSSQLExpress 2017.
SELECT * FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) as [Count], * FROM table1
) as a
WHERE [Count] BETWEEN 10 and 20;
--Giving a Column [Count] and assigning every row a unique counting without ordering something then re select again where you can provide your limits.. :)
One of the possible way to get result as below , hope this will help.
declare #start int
declare #end int
SET #start = '5000'; -- 0 , 5000 ,
SET #end = '10000'; -- 5001, 10001
SELECT * FROM (
SELECT TABLE_NAME,TABLE_TYPE, ROW_NUMBER() OVER (ORDER BY TABLE_NAME) as row FROM information_schema.tables
) a WHERE a.row > #start and a.row <= #end
If i remember correctly (it's been a while since i dabbed with SQL Server) you may be able to use something like this: (2005 and up)
SELECT
*
,ROW_NUMBER() OVER(ORDER BY SomeFields) AS [RowNum]
FROM SomeTable
WHERE RowNum BETWEEN 10 AND 20
I want to do a query to retrieve the record immediately after a record for any given record, in a result set ordered by list. I do not understand how to make use of the limit keyword in sql syntax to do this.
I can use WHERE primarykey = number, but how will limiting the result help when I will only have one result?
How would I obtain the next record with an arbitrary primary key number?
I have an arbitrary primary key, and want to select the next one ordered by date.
This will emulate the LEAD() analytic function (i. e. select the next value for each row from the table)
SELECT mo.id, mo.date,
mi.id AS next_id, mi.date AS next_date
FROM (
SELECT mn.id, mn.date,
(
SELECT id
FROM mytable mp
WHERE (mp.date, mp.id) > (mn.date, mn.id)
ORDER BY
mp.date, mp.id
LIMIT 1
) AS nid
FROM mytable mn
ORDER BY
date
) mo,
mytable mi
WHERE mi.id = mo.nid
If you just want to select next row for a given ID, you may use:
SELECT *
FROM mytable
WHERE (date, id) >
(
SELECT date, id
FROM mytable
WHERE id = #myid
)
ORDER BY
date, id
LIMIT 1
This will work most efficiently if you have an index on (date, id)
How about something like this, if you're looking for the one after 34
SELECT * FROM mytable WHERE primaryKey > 34 ORDER BY primaryKey LIMIT 1
Might be as simple as:
select *
from mytable
where datecolumn > (select datecolumn from mytable where id = #id)
order by datecolumn
limit 1
(Edited after comments)