How to select the nearest row date in SQL? - sql

I need help with this SQL query. This is my table:
| id_list | name | date_created | date_updated |
|-----------|-----------|-----------------------|---------------------|
| 1 | Laundry | 2020-10-14 12:29:14 | 2020-10-15 08:04:10 |
| 2 | Food | 2020-10-14 12:38:43 | 2020-10-15 10:45:03 |
How can I select the row with the nearest date_updated? The output has to be like this:
| id_list | name | date_created | date_updated |
|-----------|-----------|-----------------------|---------------------|
| 2 | Food | 2020-10-14 12:38:43 | 2020-10-15 10:45:03 |

If you just want the "nearest" to the current time just use the max. This will return multiple rows in case of a tie.
SELECT *
FROM A_TABLE
WHERE date_updated =
( SELECT MAX(date_updated)
FROM A_TABLE
)

If you just the one latest row, then order by and limit are sufficient:
select t.*
from mytable t
order by date_updated desc
limit 1
If you want the row that is closest to the current date/time, whether in the past or in the future, then:
select t.*
from mytable t
order by abs(julianday() - julianday(date_updated))
limit 1

Related

Select the highest value of column 2 per column 1

Given the following table P_PROV
+----+-----------+-----------+
| id | date | person_id |
+----+-----------+-----------+
| 1 |19/06/2019 | 1 |
| 2 |18/07/2010 | 2 |
| 3 |19/06/2020 | 1 |
| 4 |17/06/2020 | 2 |
| 5 |28/06/2020 | 3 |
+----+-----------+-----------+
I want this output
+----+-----------+-----------+
| id | date | person_id |
+----+-----------+-----------+
| 3 |19/06/2020 | 1 |
| 4 |17/06/2020 | 2 |
| 5 |28/06/2020 | 3 |
+----+-----------+-----------+
Putting this in words, I want to return per person the maximum date. I tried something like this
SELECT DISTINCT pp.date, pp.id FROM P_PROV pp
WHERE (SELECT MAX(aa.date)
FROM P_PROV aa) = pp.date;
This one is only returning one row (of course, because the MAX will return the maximum date only), but I really don't know how to approach this issue, any kind of help would be appreciated
ROW_NUMBER provides one way to handle this:
SELECT id, date, person_id
FROM
(
SELECT t.*, ROW_NUMBER() OVER (PARTITION BY person_id ORDER BY date DESC) rn
FROM yourTable t
) t
WHERE rn = 1;
Oracle has a fun way to do this using aggregation:
select max(id) keep (dense_rank first order by date desc) as id,
max(date) as date, person_id
from P_PROV
group by person_id;
Given that your ids are increasing, this probably also does what you want:
select max(id) as id, max(date) as date, person_id
from P_PROV
group by person_id;

How do I select rows with maximum value?

Given this table I want to retrieve for each different url the row with the maximum count. For this table the output should be: 'dell.html' 3, 'lenovo.html' 4, 'toshiba.html' 5
+----------------+-------+
| url | count |
+----------------+-------+
| 'dell.html' | 1 |
| 'dell.html' | 2 |
| 'dell.html' | 3 |
| 'lenovo.html' | 1 |
| 'lenovo.html' | 2 |
| 'lenovo.html' | 3 |
| 'lenovo.html' | 4 |
| 'toshiba.html' | 1 |
| 'toshiba.html' | 2 |
| 'toshiba.html' | 3 |
| 'toshiba.html' | 4 |
| 'toshiba.html' | 5 |
+----------------+-------+
What SQL query do I need to write to do this?
Try to use this query:
select url, max(count) as count
from table_name
group by url;
use aggregate function
select max(count) ,url from table_name group by url
From your comments it seems you need corelated subquery
select t1.* from table_name t1
where t1.count = (select max(count) from table_name t2 where t2.url=t1.url
)
If row_number support on yours sqllite version
then you can write query like below
select * from
(
select *,row_number() over(partition by url order by count desc) rn
from table_name
) a where a.rn=1

SQL Server partition by gives duplicate records

I have following table:
Date | ID | firstname
---------+----+------------
20161128 | 1 | Adam
20161128 | 2 | Steve
20161128 | 2 | Steve
20161128 | 3 | Aaron
20161129 | 1 | Adam
20161129 | 2 | Steve
20161129 | 2 | Steve
20161129 | 3 | Aaron
I want to get the first row by ID for one particular date.
So what I had was:
SELECT *
FROM tableA
WHERE Date = 20161128
this however, gives all records. So I used the partition over function:
SELECT
*,
row_number() over(partition by ID order by Date desc)
FROM tableA
WHERE Date = 20161128
In this case, I get following result:
Date | ID | firstname | rownum
---------+----+-----------+-------
20161129 | 1 | Adam | 1
20161129 | 1 | Adam | 2
20161129 | 2 | Steve | 1
20161129 | 2 | Steve | 2
20161129 | 2 | Steve | 3
20161129 | 2 | Steve | 4
20161129 | 2 | Steve | 5
20161129 | 2 | Steve | 6
20161129 | 3 | Aaron | 1
20161129 | 3 | Aaron | 2
As you can see, Most ID's appear 2 times. (ID 2 even appears 6 times). In other cases, I see a record appear 10 times even though it would only have one record if I used the first query.
Any idea why this happens and how this can be fixed? My guess would be the date/where clause, but I don't see how this can effect the result this much.
You need a WHERE clause if you want to filter the records:
SELECT a.*
FROM (SELECT a.*,
row_number() over(partition by ID order by Date desc) as seqnum
FROM tableA a
WHERE a.Date = '20161128'
) a
WHERE seqnum = 1;
This will return one row per date per id number.
You can replace
SELECT *,
row_number() over(partition by ID order by Date desc)
FROM tableA
WHERE Date = 20161128
to
SELECT *
FROM tableA
WHERE ID = (select min(ID) from tableA )
This will only display the first instance.
Select * from
(SELECT *,
rownum=row_number() over(partition by PersonID_EXT order by SnapshotDate desc)
FROM tableA
WHERE Date = 20161128)x where rownum =1

netezza delete records with different timestamp field where specific fields are the same

I have a netezza table where data can get overlapped when updated however a timestamp field on each associated would be different. For instance:
+-----------------+----------+-------------+-----+
| ts | first_nm | last_nm | val |
+-----------------+----------+-------------+-----+
| 4/1/2015 4:15pm | ben | bloomington | 12 |
| 4/1/2015 4:20pm | ben | bloomington | 4.5 |
| 4/1/2015 4:20pm | andrew | bloomberg | 2.8 |
+-----------------+----------+-------------+-----+
Id like to keep the following records and delete the earlier timestamp for ben bloomington:
+-----------------+----------+-------------+-----+
| ts | first_nm | last_nm | val |
+-----------------+----------+-------------+-----+
| 4/1/2015 4:20pm | ben | bloomington | 4.5 |
| 4/1/2015 4:20pm | andrew | bloomberg | 2.8 |
+-----------------+----------+-------------+-----+
so, based on first_nm and last_nm being distinct how can I just keep the latest ts with the latest value?
I think I could use row_number() function but I am unsure how to implement this in my delete statement.
You can delete all rows that aren't the latest timestamp using the example below. I added the windowed function row_number() as an example.
delete from <table>
where rowid in
(
select rwid
from ( select rowid as rwid
, row_number() over(partition by first_nm,last_nm order by ts desc) as rown
from <table>
) sub
where sub.rown>1
);
The shorter solution that should do the same is:
DELETE FROM table t
WHERE
EXISTS (SELECT * FROM table
WHERE t.rwid < rwid
AND t.first_nm = first_nm
AND t.last_nm = last_nm)

Display multiple highest values in Oracle

At the moment to display the highest value in my query I am using:
ORDER BY Height DESC
) T
WHERE RowNum = 1
This displays the highest value, for example 10, But what if two entries are both of the same value 10.
How can I make it so it shows both of the joint highest values?
use in Oracle, use the rank analytic
select a, b
from (select a, b, rank() over (order by height desc) rnk
from your_table)
where rnk = 1;
One solution would be to use a CTE
Using a CTE
;WITH q AS (
SELECT MAX(Height) AS maxHeight
FROM YourTable
)
SELECT *
FROM YourTable
INNER JOIN q ON q.maxHeight = Yourtable.Height
or a plain where clause with a subselect
SELECT *
FROM YourTable
WHERE Height = (SELECT MAX(Height) FROM YourTable)
Personally, I prefer using a CTE as it doesn't clutter up the statement (well, not true in this simple case but in practice, I often find it far more readable than subselects).
This will do and it's every simple too,
Select height from table where height=(select max(height) from table)
here you have without subqueries, it's more complicated but it was funny to created.
select ifnull(#d,#d:=actor_id),actor_id,if(#d>actor_id,1,0)as t
from t1 having t=0 order by actor_id desc;
here is the example in my computer.
mysql> desc t1;
+-------------+----------------------+------+-----+---------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------------------+------+-----+---------------------+-------+
| actor_id | smallint(5) unsigned | NO | | 0 | |
| first_name | varchar(45) | NO | | NULL | |
| last_name | varchar(45) | NO | | NULL | |
| last_update | timestamp | NO | | 0000-00-00 00:00:00 | |
+-------------+----------------------+------+-----+---------------------+-------+
4 rows in set (0.00 sec)
mysql> select * From t1 order by actor_id desc limit 5;
+----------+------------+-----------+---------------------+
| actor_id | first_name | last_name | last_update |
+----------+------------+-----------+---------------------+
| 20001 | test | test | 2012-12-13 09:12:50 |
| 20001 | test | test | 2012-12-13 09:12:51 |
| 2000 | b | a | 0000-00-00 00:00:00 |
| 2000 | b | a | 0000-00-00 00:00:00 |
| 2000 | b | a | 0000-00-00 00:00:00 |
+----------+------------+-----------+---------------------+
5 rows in set (0.00 sec)
mysql> select ifnull(#d,#d:=actor_id),actor_id,if(#d>actor_id,1,0)as t
-> from t1 having t=0 order by actor_id desc;
+-------------------------+----------+---+
| ifnull(#d,#d:=actor_id) | actor_id | t |
+-------------------------+----------+---+
| 20001 | 20001 | 0 |
| 20001 | 20001 | 0 |
+-------------------------+----------+---+
2 rows in set (0.00 sec)