How to use MAX and TOP in SQL Query in ORACLE? - sql

Suppose I have following table
ID ITEM QUANTITY DATE
1 A 50 Jan 3, 2013
2 B 80 Jan 1, 2013
3 C 70 Jan 5, 2013
4 D 80 Jan 4, 2013
I have to make a single query which will fetch the record which has highest quantity and highest date. For example, end result should be
4 D 80 Jan 4, 2013
Update: First of all I have to pick the records which have highest quantity. In this case it would be record no. 2 and 4. Then I have to again filter out from these two records which have highest date
How should I make SQL query in ORACLE?

To get those data you could write a query similar to this one:
select id
, item
, quantity
, date
from (select id
, item
, quantity
, date
from your_table
order by quantity desc, date desc
)
where rownum = 1

Related

SQL Query to sort date based on two column

I have following data in table RATING and i want to sort this based on Rating and Year.
Database MS SQL Server
Unsorted data in Table
ID PlayerName Rating Year
1 A 8 2022
2 B 8 2022
3 C 0 2022
4 A 7 2020
5 B 6 2020
6 C 6 2020
7 E 5 2020
8 D 5 2020
9 D 5 2022
Data should show as below
ID PlayerName Rating Year
1 A 8 2022
2 B 8 2022
3 D 5 2022
9 C 0 2022
4 A 7 2020
5 B 6 2020
6 C 6 2020
7 E 5 2020
8 D 5 2020
I am not able to get it right i used following Query
SELECT ID, PlayerName, Rating, Year
FROM RATING
Where Year IN (SELECT Year from Rating)
order by year DESC
but it doesn't get the correct order as i am not able to use order by clause in sub query as it generates error The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified.
Event two column sort is not working properly
SELECT ID, PlayerName, Rating, Year
FROM RATING
order by Rating, Year
You can try to ORDER BY year DESC first then Rating DESC
SELECT ID, PlayerName, Rating, [Year]
FROM RATING
order by [Year] DESC,Rating DESC
Year is a keyword in sqlserver, I would use brackets to contain it.
Your attempt is not bad so far. But there are two things you need to change.
First: The column with the higher priority for your sorting is the column "year", so this has to be used first, and then the column "rating".
Second: You must add the key word "DESC" to begin with the newest year and the highest ranking.
So your query should be this one:
SELECT * FROM rating ORDER BY year DESC, rating DESC;
You can see this is working here: db<>fiddle
If you can rename the columns on your DB, I recommend to do not use SQL key words as column names (in your example, this the column "year") and to do not use column names that are identic to the table names (in your case, you could rename the table "rating" to "ratings" or similar).
Both of this is of course possible, but could sometimes be bad to read and let increase the risk of issues.

Extract column from SQL table based on another column if the same table

I m using POSTGRESQL.
Table of PURCHASES looks like this:
ID | CUSTOMER_ID | YEAR
1 1 2011
2 2 2012
3 2 2012
4 1 2013
5 3 2014
6 3 2014
7 3 2015
I need to extract 'ID' of the purchase with the latest 'date/year' for each CUSTOMER.
For example for CUSTOMER_ID 1 the year s 2013 which correcponds with id '4'.
I need to get ONE column as a return data structure.
PS. i m stuck with this kinda simple task )))
If you want one row per customer, you can use distinct on:
select distinct on (customer_id) id
from purchases
order by customer_id, year desc;
This returns one column which is an id from the most recent year for that customer.
This should work, but doesn't look too pretty...
SELECT DISTINCT ON(CUSTOMER_ID) ID FROM PURCHASES P
WHERE (CUSTOMER_ID,YEAR) =
(SELECT CUSTOMER_ID,MAX(YEAR) FROM PURCHASES WHERE CUSTOMER_ID = P.CUSTOMER_ID
GROUP BY CUSTOMER_ID);
So for input
ID | CUSTOMER_ID | YEAR
1 1 2011
2 2 2012
3 2 2012
4 1 2013
5 3 2014
6 3 2014
7 3 2015
It will return
id
4
2
7
Meaning:
For the lowest CUSTOMER_ID (it is 1) the id is 4 (year 2013)
Next we have CUSTOMER_ID (it is 2) the id is 2 (year 2012)
Lastly the CUSTOMER_ID (it is 3) the id is 7 (year 2015)
The idea behind this:
Group by CUSTOMER_ID
For each group select max(year)
While looping over all records - if Customer_id and year equals those from number 2. then select ID from this record.
Without DISTINCT ON(CUSTOMER_ID) it would return 2 records
for CUSTOMER_ID = 2, because for both years 2012 it would find some records while looping.
If you write in the beginning instead of:
SELECT DISTINCT ON(CUSTOMER_ID) ID FROM PURCHASES P
this code:
SELECT DISTINCT ON(CUSTOMER_ID) * FROM PURCHASES P
then you will see everything clearly.
Use row_number() analytic function with partition by customer_id to select by each customer with descending ordering by year ( if ties occur for year values [e.g. they're equal], then the below query brings the least ID values for each customer_id. e.g. 4, 2, 7 respectively )
WITH P2 AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY CUSTOMER_ID ORDER BY YEAR DESC) AS RN,
*
FROM PURCHASES
)
SELECT ID FROM P2 WHERE RN = 1
Demo

How do I "dedup" rows based on most recently updated

Lets say I have a table whose content looks like
ID Name Last Update
============================
1 A 1 JAN 2018
1 A 2 JAN 2018
1 A 3 JAN 2018
2 B 3 JAN 2018
2 B 6 JAN 2018
I want to get the result
ID Name Last Update
============================
1 A 3 JAN 2018
2 B 6 JAN 2018
How can I do it?
I tried to group by ID but, how do I get the most recent?
While #Nik's solution can work in situations where there are either no ties for the MAX(date) values (or it doesn't matter which tie value gets selected and whether this produces multiple output rows), an alternative approach is to group all records by ID sort all records belonging to one group by date in descending order and then pick the very first result row per group.
This can be achieved by using the SQL standard window function ROW_NUMBER() like this:
SELECT ID, NAME, DATE
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY ID
ORDER BY DATE DESC) RN
, ID
, NAME
, DATE
FROM <TABLE_NAME>
)
WHERE RN = 1;
You could use a query like this to get the results that you need:
SELECT *
FROM table
WHERE (ID, date) IN (SELECT
ID, MAX(Last Update)
FROM table
GROUP BY ID)

Limiting output with different criterias

I have the following SQL statement:
select
row_number() over(),
car, group, yearout
from (select..... )inner
where year(inner.yearout) between '2010' and '2030'
order by inner.group)temp
the output is like
1 test1 1 2010
2 test2 1 2010
3 test3 1 2012
4 test1 2 2010
5 test1 3 2011
and so on.
There is another table called outerno with is filled like:
no yearo amnt
1 2010 10
2 2010 15
3 2010 5
4 2010 10
5 2010 15
6 2010 8
1 2011 4
2 2011 15
and so on.
There are 6 groups in the table for each year.
Now the problem is that I need to limit the output of the query as stated in the outerno table.
So I need the first 10 row for 2010 for group 1, the first 15 rows of 2010 for group 2 and so on. For each year and group there is a value in the outerno.
I tried to use row_number but I don't know how to limit the output in this way since I would be needing for example rows 1-10, 50-65, 83-88 and so on.
Any idea on how to do this?
Thanks in advance for all your help.
TheVagabond
You'd use ROW_NUMBER() to give you record numbers per group. Then add a WHERE clause to only get row numbers up to the desired number. In ROW_NUMBER's ORDER BY you can spcify which records to prefer.
select row_number() over (), car, group, yearout
from
(
select
row_number() over (partition by inner.group, inner.yearout order by inner.car) as rn,
inner.car, inner.group, inner.yearout
from (select..... ) inner
where inner.yearout between '2010' and '2030'
order by inner.group
) all_records
where all_records.rn <=
(
select amnt
from outerno
where outerno.year = all_records.yearout
and outerno.no = all_records.group
);
BTW: I wouldn't choose group for a column name, as it is a reserved word in SQL.

SQL query to return rows in multiple groups

I have a SQL table with data in the following format:
REF FIRSTMONTH NoMONTHS VALUE
--------------------------------
1 2 1 100
2 4 2 240
3 5 4 200
This shows a quoted value which should be delivered starting on the FIRSTMONTH and split over NoMONTHS
I want to calculate the SUM for each month of the potential deliveries from the quoted values.
As such I need to return the following result from a SQL server query:
MONTH TOTAL
------------
2 100 <- should be all of REF=1
4 120 <- should be half of REF=2
5 170 <- should be half of REF=2 and quarter of REF=3
6 50 <- should be quarter of REF=3
7 50 <- should be quarter of REF=3
8 50 <- should be quarter of REF=3
How can I do this?
You are trying extract data from what should be a many to many relationship.
You need 3 tables. You should be able to write a JOIN or GROUP BY select statement from there. The tables below don't use the same data values as yours, and are merely intended for a structural example.
**Month**
REF Month Value
---------------------
1 2 100
2 3 120
etc.
**MonthGroup**
REF
---
1
2
**MonthsToMonthGroups**
MonthREF MonthGroupREF
------------------
1 1
2 2
2 3
The first part of this query gets a set of numbers between the start and the end of the valid values
The second part takes each month value, and divides it into the monthly amount
Then it is simply a case of grouping each month, and adding up all of the monthly amounts.
select
number as month, sum(amount)
from
(
select number
from master..spt_values
where type='p'
and number between (select min(firstmonth) from yourtable)
and (select max(firstmonth+nomonths-1) from yourtable)
) numbers
inner join
(select
firstmonth,
firstmonth+nomonths-1 as lastmonth,
value / nomonths as amount
from yourtable) monthly
on numbers.number between firstmonth and lastmonth
group by number