Combine two sql select queries (in postgres) with LIMIT statement - sql

I've got a table and I want a query that returns the last 10 records created plus the record who's id is x.
I'm trying to do -
SELECT * FROM catalog_productimage
ORDER BY date_modified
LIMIT 10
UNION
SELECT * FROM catalog_productimage
WHERE id=5;
But it doesn't look like I can put LIMIT in there before UNION. I've tried adding another column and using it for sorting -
SELECT id, date_modified, IF(false, 1, 0) as priority FROM catalog_productimage
UNION
SELECT, id, date_modified, IF(true, 1, 0) as priority FROM catalog_productimage
WHERE id=5
ORDER BY priority, date_modified
LIMIT 10;
but I'm not making much progress..

Just checked that this will work:
(SELECT * FROM catalog_productimage
ORDER BY date_modified
LIMIT 10)
UNION
SELECT * FROM catalog_productimage
WHERE id=5;

This will give you records from 10th to 20th and should get you started.i will reply back with SQLfiddle
SELECT *
FROM (SELECT ROW_NUMBER () OVER (ORDER BY cat_id) cat_row_no, a.* FROM catalog_productimage a where x=5)
WHERE cat_row_no > 10 and cat_row_no <20

Related

SQL Offset return last row if no match

I want to return the book that matches the offset/order and if there isn't one I want to return the last book.
WITH BOOKS AS (
SELECT 'book_1' AS name, 0 AS order_ UNION ALL
SELECT 'book_2', 1 UNION ALL
SELECT 'book_3', 2
)
SELECT name from BOOKS ORDER BY order_ asc OFFSET 0 limit 1;
It should return:
Offset 0 - book_1
Offset 1 - book_2
Offset 2 - book_3
Offset 3+ - book_3
It works fine for offset 0,1,2 but not really sure how I can make it work for offset bigger than 3.
Fiddle
Thanks
If when you will create your own function which returns table data then you can do it easily using the if-exists (or you can use any logic) statements in the function. But doing this using one query is more difficult. For that, I choose the second way, so using a query.
My Sample Query:
with mytable as materialized
(
select
*,
row_number() over (order by order_) as r_num
from
test.test_table
)
select * from (
(SELECT * from mytable order by r_num offset 17 limit 1)
union
(SELECT * from mytable where r_num = (select max(r_num) from mytable))
) t1
limit 1;
This is my logic variant, maybe someone has another best variants.

Pagination of large dataset

I have a query that returns a large (10000+ rows) dataset. I want to order by date desc, and display the first 40 results. Is there a way to run a query like this that only retrieves those 40 results without retrieving all 10000 first?
I have something like this:
select rownum, date, * from table
order by date desc
This selects all the data and orders it by date, but the rownum is not in order so it is useless for selecting only the first 40.
ROW_NUMBER() over (ORDER BY date desc) AS rowNumber
^ Will display a rownumber in order, but I can't use it in a where clause because it is a window function. I could run this:
select * from (select ROW_NUMBER() over (ORDER BY date desc) AS rowNumber,
rownum, * from table
order by date desc) where rowNumber between pageStart and pageEnd
but this is selecting all 10000 rows. How can I do this efficiently?
SELECT *
FROM (SELECT *
FROM table
ORDER BY date DESC)
WHERE rownum <= 40
will return the first 40 rows ordered by date. If there is an index on date that can be used to find these rows, and assuming statistics are up to date, Oracle should choose to use that index to identify the 40 rows that you want and then do 40 single-row lookups against the table to retrieve the rest of the data. You could throw a /*+ first_rows(40) */ hint into the inner query if you want though that shouldn't have any effect.
For a more general discussion on pagination queries and Top N queries, here's a nice discussion from Tom Kyte and a much longer AskTom discussion.
Oracle 12c has introduced a row limiting clause:
SELECT *
FROM table
ORDER BY "date" DESC
FETCH FIRST 40 ROWS ONLY;
In earlier versions you can do:
SELECT *
FROM ( SELECT *
FROM table
ORDER BY "date" DESC )
WHERE ROWNUM <= 40;
or
SELECT *
FROM ( SELECT *,
ROW_NUMBER() OVER ( ORDER BY "date" DESC ) AS RN
FROM table )
WHERE RN <= 40;
or
SELECT *
FROM TEST
WHERE ROWID IN ( SELECT ROWID
FROM ( SELECT "Date" FROM TEST ORDER BY "Date" DESC )
WHERE ROWNUM <= 40 );
Whatever you do, the database will need to look through all the values in the date column to find the 40 first items.
You don't need a window function. See
http://www.techonthenet.com/oracle/questions/top_records.php
for an answer to your problem.

Oracle SQL: Filtering by ROWNUM not returning results when it should

I have the following SQL I'm trying to run against an Oracle database:
SELECT *
FROM(SELECT crd.Request_ID,
crd.Requested_Start_Date Scheduled_Start,
crd.Actual_Start_Date Start_Date,
crd.Actual_Completion_Date Finish_Date,
crd.Status_Code
FROM ((SELECT fcr.Request_ID,
fcr.Requested_Start_Date,
fcr.Actual_Start_Date,
fcr.Actual_Completion_Date,
fcr.Status_Code,
fcr.Oracle_Session_ID,
fcr.Responsibility_ID
FROM Applsys.FND_Concurrent_Requests fcr
WHERE fcr.Oracle_Session_ID IS NOT NULL)
UNION ALL (SELECT xcr.Request_ID,
xcr.Requested_Start_Date,
xcr.Actual_Start_Date,
xcr.Actual_Completion_Date,
xcr.Status_Code,
xcr.Oracle_Session_ID,
xcr.Responsibility_ID
FROM xxfnd.emr_FND_Concurrent_Requests xcr
WHERE xcr.Oracle_Session_ID IS NOT NULL)) crd
WHERE crd.Actual_Start_Date >= to_Date('06/01/2014', 'MM/DD/YYYY')
ORDER BY 3, 1)
WHERE Rownum < (1000000 * to_Number(:X))
AND ROWNUM >= (1000000 * (to_Number(:X)-1))
For :X set to 1, I get (as expected) the first 999,999 rows of data. However, when I set :X to 2, nothing is returned. This despite the fact that when I use Select Count(*) in place of Select * and drop the Where clause entirely the results indicate there are over 9 million records returned by the subquery.
Any help would be much appreciated.
You cannot use rownum like this. rownum is calculated when the values are actually returned from the query -- only when a row is returned. Hence, the statement:
where rownum = 2
will never return a value, because there needs to a be a "1" before a "2".
If you are using Oracle 12+, you can use the offset clause with fetch first <n> rows only. In earlier versions, you can use row_number() over () to calculate a row number as a column and use that in the where.
Actually, your query already uses a subquery, so you can do something like:
select *
from (select . . .,
row_number() over (order by Request_ID, Actual_Start_Date) as rn
. . .
) t
WHERE rn < (1000000 * to_Number(:X) and)
rn >= (1000000 * (to_Number(:X)-1))
The reason is because you're using rownum in the outermost query, and you're expecting it to return rows if you specify that rownum >= <some number>. The only number that will ever satisfy that condition is 1, since rownum is assigned on the fly as rows are returned.
What you need to do instead is to assign the rownum in the main subquery and give it an alias, and then refer to the alias in the outer query - like so:
with main_results as (SELECT crd.Request_ID,
crd.Requested_Start_Date Scheduled_Start,
crd.Actual_Start_Date Start_Date,
crd.Actual_Completion_Date Finish_Date,
crd.Status_Code
FROM (SELECT fcr.Request_ID,
fcr.Requested_Start_Date,
fcr.Actual_Start_Date,
fcr.Actual_Completion_Date,
fcr.Status_Code,
fcr.Oracle_Session_ID,
fcr.Responsibility_ID
FROM Applsys.FND_Concurrent_Requests fcr
WHERE fcr.Oracle_Session_ID IS NOT NULL
UNION ALL
SELECT xcr.Request_ID,
xcr.Requested_Start_Date,
xcr.Actual_Start_Date,
xcr.Actual_Completion_Date,
xcr.Status_Code,
xcr.Oracle_Session_ID,
xcr.Responsibility_ID
FROM xxfnd.emr_FND_Concurrent_Requests xcr
WHERE xcr.Oracle_Session_ID IS NOT NULL) crd
WHERE crd.Actual_Start_Date >= to_Date('06/01/2014', 'MM/DD/YYYY')
ORDER BY 3, 1)
SELECT *
FROM (select Request_ID,
Requested_Start_Date Scheduled_Start,
Actual_Start_Date Start_Date,
Actual_Completion_Date Finish_Date,
Status_Code,
rownum rn
from main_results)
WHERE rn < (1000000 * to_Number(:X))
AND rn >= (1000000 * (to_Number(:X)-1));

Select the 100 lowest values in SQL?

I've been looking around for a while, and it seems it cant be found anywhere. I want to know how do you select the 100 highest and the 100 lowst values in a column? The MIN-function only chooses the lowest one and the MAX the highest one.
Anyone out there who knows how you do this?
SQL Server
Top 100 Highest
SELECT TOP 100 * FROM MyTable
ORDER BY MyCol DESC
Top 100 Lowest
SELECT TOP 100 * FROM MyTable
ORDER BY MyCol ASC
MySQL
Top 100 Highest
SELECT * FROM MyTable
ORDER BY MyCol DESC LIMIT 100
Top 100 Lowest
SELECT * FROM MyTable
ORDER BY MyCol ASC LIMIT 100
You can do it as below,
Highest
select * from
tablename
order by
column DESC
limit 0,100
Lowest
select * from
tablename
order by
column ASC
limit 0,100
EDIT
For SQL Server replace select * from with select TOP 100 * from
The SELECT TOP clause is used to specify the number of records to return.
Use sorting in ascending and descending order and limit output to 100
if you use Sql server
you can order query desc and select top 1000 like :
select top(1000) * from mytable order by value desc
Try this:
DECLARE #V_MaxNo INT;
SELECT #V_MaxNo = COUNT(1) FROM TABLE_NAME WHERE (CONDITION_PART_AS_REQUIRED);
SELECT COLUMN_LIST
FROM (SELECT ROW_NUMBER() OVER (ORDER BY [Order_by_column_list_with_ASC/DESC]) rowNo, COLUMN_LIST
FROM TABLE_NAME) A
WHERE (100 - rowNo) >= 0 or (#V_MaxNo - rowNo) < 100
Here's another approach independent from db engine
MAX
select * from MyTable a where 100 > (select count(id) from MyTable b where a.MyCol <= b.MyCol) order by MyCol desc

SQL Server query for top rows to select with condition

I want to skip first 5 records and then select 10 records
I have a column email in table user. Here I am trying to select top 10 unique rows from table user using this query
select DISTINCT TOP 10 email from user
Now I am trying to select top 10 unique rows from table skipping the first 5 records
select DISTINCT SKIP 5 TOP 10 email from user
which is not done and return error.. can anyone help me
SELECT A.NAME FROM
(SELECT distinct RANK() OVER(ORDER BY NAME) RNK,NAME FROM USERS) A
WHERE A.RNK>4 AND A.RNK<16
Using LIMIT will not guarantee you that you will get top rows with proper order.
If you use ANALYTIC functions, it will give you proper results.
SQL_LIVE_DEMO
Here is one way to do it. I like to use Common Table Expressions for some things like this because it makes the query easy to understand, although this isn't particularly complicated.
WITH CTE AS
(
Select Distinct Email From User
)
,
CTE1 AS
(
Select Email, ROW_NUMBER() over (ORDER BY Email) AS RowNumber
From CTE
)
Select Top 10 * From CTE1 Where RowNumber > 5
with t2 as
(
select t1.*,
row_number() over (order by id) rn
from
(select email, max(id) as id from [user] group by email) as t1
)
select * from t2 where rn between 5 and 10
How about this:
SELECT *
FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY email) AS row
FROM user ) a
WHERE row > 5 and row <= 10
I think you are using SKIP incorrectly, it should be part of the ORDER BY clause.
SELECT DISTINCT TOP(10) Email FROM TableName WHERE Email not in (SELECT TOP(5) Email From TableName)
You can try this code, in this query fetch distinct 10 email ids skip 5 records as you say in this question.