This question already has answers here:
How to get second largest or third largest entry from a table [duplicate]
(12 answers)
Closed 4 years ago.
I have the following data:
id date mia
1 1/1/2017 3
1 1/2/2017 1
1 1/3/2017 2
2 1/4/2017 1
2 1/5/2017 4
2 1/6/2017 6
.
.
.
.
and so on.
If I give input as id=1 I should fetch record of 2017-02-01 and if input id=2 then record of 2017-05-01 i.e record of previous month of the highest date.
You could use:
SELECT *
FROM (SELECT *, ROW_NUMBER() OVER(PARTITION BY id ORDER BY mia DESC) AS rn
FROM table) sub
WHERE rn = 2;
you may not define a column named as date, instead i use date_.
For former versions you may refer to #lad2025 's answer, if you're on oracle12c, you may query with the following :
select min(date_) min_date
from
(
select date_
from mytable
where id = &i_id
group by id, date_
order by date_
fetch first 2 rows only
);
Related
This question already has answers here:
How to use RANK() in SQL Server
(8 answers)
Closed 3 years ago.
How can I create a sequential value based on two rows within a table, for example, let's say I have a table containing an employee's ID and work state. I would expect the following values:
ID State Expected Value
-----------------------------
1 NY 1
1 PA 2
1 NY 1
2 NC 1
2 FL 2
2 MN 3
You can use dense_rank():
select t.*,
dense_rank() over (partition by id order by state) as expected
from t;
I have index_date information for IDs and I want to extract baseline ( information between index_date and Index_date minus 6 months). I want to do this without using Cartesian product.
Total Table
ID index_date detail
1 01Jan2012 xyz
1 01Dec2011 pqr
1 01Nov2010 pqr
2 26Feb2013 abc
3 02Mar2013 abc
3 02Feb2013 ert
3 02Jan2013 tyu
4 07May2015 rts
I have a table A extracted from Total which has the index_dates:
ID index_date index_detail
1 01Jan2012 xyz
2 26Feb2013 abc
3 02Mar2013 abc
4 07May2015 rts
I want to extract baseline periods data for IDs in A from from the Total table
Table want :
ID date index_date detail index_detail
1 01Jan2012 01Jan2012 xyz xyz
1 01Dec2011 01Jan2012 pqr xyz
2 26Feb2013 26Feb2013 abc abc
3 02Mar2013 02Mar2013 abc abc
3 02Feb2013 02Mar2013 ert abc
3 02Jan2013 02Mar2013 tyu abc
4 07May2015 07May2015 rts rts
code used :
create table want as
select a.* , b.date,b.detail
from table_a as a
right join
Total as b
on a.id = b.id where
a.index_date > b.date
AND b.date >= add_months( a.index_date, -6)
;
But this requires Cartesian Product. Is there a way to do this without requiring Cartesian product.
DBMS - Hive
Sorry, I don't know it.
I'll give the solution on pure SQL for MySQL 8+ - maybe you'll find the way to convert it to Hive syntax.
SELECT id,
index_date date,
FIRST_VALUE(index_date) OVER (PARTITION BY ID ORDER BY STR_TO_DATE(index_date, '%d%b%Y') DESC) index_date,
detail,
FIRST_VALUE(detail) OVER (PARTITION BY ID ORDER BY STR_TO_DATE(index_date, '%d%b%Y') DESC) index_detail
FROM test
ORDER BY 1 ASC, 2 DESC
fiddle
I would recommend three steps:
Convert the date to a number.
Find the minimum date in a six month period.
Get the first value in that group.
This looks like:
select t.*, t2.index_date, t2.detail
from (select t.*,
min(index_date) over (partition by id
order by months
range between 6 preceding and current row
) as sixmonth_date
from (select t.*,
year(index_date) * 12 + month(index_date) as months
from total t
) t
) t left join
total t2
on t2.id = t.id and t2.index_date = t.sixmonth_date;
This is marginally simpler if first_value() accepts range window frames -- but I'm not sure if it does. It is worth trying, though:
select t.*,
min(index_date) over (partition by id
order by months
range between 6 preceding and current row
) as sixmonth_date,
first_value(detail) over (partition by id
order by months
range between 6 preceding and current row
) as sixmonth_value
from (select t.*,
year(index_date) * 12 + month(index_date) as months
from total t
) t
This question already has answers here:
Fetch the rows which have the Max value for a column for each distinct value of another column
(35 answers)
Get top results for each group (in Oracle)
(5 answers)
Select latest row for each group from oracle
(3 answers)
How to get only one record for each duplicate rows of the id in oracle?
(3 answers)
Closed 3 years ago.
Below you can find my table with values (there are no constraints on my table):
SELECT DISTINCT * FROM khalil;
outputs:
ID VALUE
-- -------
1 yassine
1 khalil
2 amine
I need to get the first row when I have duplicate values.
I have two rows with id = 1 so, in this case, I need that the first one,
which is id = 1 and value = 'yassine'
SELECT * FROM khalil
WHERE ROWID IN (SELECT MIN(ROWID) FROM khalil GROUP BY id)
ORDER BY id
This will return the first row for each id.
If you don't really care which value you'll get (unless there's something you can use to distinguish values), aggregates - such as min or max - can help:
SQL> select id,
2 max(value) value
3 from khalil
4 group by id
5 order by id;
ID VALUE
---------- --------------------
1 yassine
2 amine
SQL>
Alternatively, using analytic functions (such as row_number, which lets you sort values), you'd do it as follows:
SQL> with temp as
2 (select id,
3 value,
4 row_number() over (partition by id order by value desc) rn
5 from khalil
6 )
7 select id,
8 value
9 from temp
10 where rn = 1
11 order by id;
ID VALUE
---------- --------------------
1 yassine
2 amine
SQL>
This question already has answers here:
Fetch the rows which have the Max value for a column for each distinct value of another column
(35 answers)
GROUP BY with MAX(DATE) [duplicate]
(6 answers)
Select First Row of Every Group in sql [duplicate]
(2 answers)
Oracle SQL query: Retrieve latest values per group based on time [duplicate]
(2 answers)
Return row with the max value of one column per group [duplicate]
(3 answers)
Closed 3 years ago.
I have the table ABC with the following data
Id Name Date Execution id
-- ---- --------- -------------
1 AA 09SEP2019 11
1 AA 08SEP2019 22
1 AA 07SEP2019 33
2 BB 09SEP2019 44
2 BB 08SEP2019 55
2 BB 07SEP2019 66
And I want to get for every distinct ID in the table its max date. So the result set must be as the following
Id Name Date Execution id
-- ---- --------- -------------
1 AA 09SEP2019 11
2 BB 09SEP2019 44
The query that returns the result I need
WITH MaxDate as (
SELECT Id,Name,Max(Date) from ABC group by Id,Name
)
SELECT view1.*, view2.exection_id
from
MaxDate view1,
ABC view2
WHERE
view1.date=view2.date and
view1.name=view2.name;
I don't like to get the max date for the distinct ID by this way. May be there is another way ? Might be there is more easiest way?
One way is to use RANK:
WITH cte AS (
SELECT ABC.*, RANK() OVER(PARTITION BY Id,Name ORDER BY Date DESC) rnk
FROM ABC
)
SELECT *
FROM cte
WHERE rnk = 1
ORDER BY id;
You can use keep dense_rank last do to this in one level of query, as long as you only want one or a small number of column retained:
select id,
name,
max(date_) as date_,
max(execution_id) keep (dense_rank last order by date_) as execution_id
from abc
group by id, name
order by id;
ID NAME DATE_ EXECUTION_ID
---------- ---- ---------- ------------
1 AA 2019-09-09 11
2 BB 2019-09-09 44
If ID and name are not always the same, and you want the name form the latest date too, then use the same pattern:
select id,
max(name) keep (dense_rank last order by date_) as name,
max(date_) as date_,
max(execution_id) keep (dense_rank last order by date_) as execution_id
from abc
group by id
order by id;
which gets the same result with your sample data.
With lots of columns it's probably simpler to use a subquery (CTE or inline view) with a ranking function and a filter (as #Lukasz shows).
With NOT EXISTS:
select t.* from ABC t
where not exists (
select 1 from ABC
where "Id" = t."Id" and "Name" = t."Name" and "Date" > t."Date"
)
I used and name = t.name only because you have it in your code.
If it is not needed you can remove it.
See the demo.
Results:
Id | Name | Date | Execution id
-: | :--- | :---------| -----------:
1 | AA | 09-SEP-19 | 11
2 | BB | 09-SEP-19 | 44
Suppose I have the next SQL table, with these sample values:
ID Date User Publish
----------------------------------
1 05/20/16 Peter 1
2 05/20/16 Peter 2 <= Discarded
3 05/20/16 John 2
4 05/28/16 John 1
5 05/28/16 John 2 <= Discarded
6 07/01/16 Peter 2
7 07/01/16 John 2
What I want to get is a query to select all rows but in case there are two rows for the same date and user, retrieve the one with 'Publish' value to '1', so in the example I get the rows 1, 3, 4, 6 and 7.
I resolve the problem programmatically but I wonder if exists a way to solve it with a proper sql query.
Any help will be appreciated.
This will discard all but the first row (ordered by publish) for each group of date and user:
SELECT ID, "Date", User, Publish
FROM (
SELECT t.*,
ROW_NUMBER() OVER ( PARTITION BY "Date", User ORDER BY Publish ) AS rn
FROM table_name t
)
WHERE rn = 1;