mysql query with group by and order by - sql

I have a table like this:
.--------------------------------.
| Name | XX | Date |
.--------------------------------.
| N1 | 5 | 2009-05-01 |
| N1 | 10 | 2008-01-08 |
| N2 | 8 | 2009-02-02 |
.________________________________.
My result should be this:
.------------.
| Name | XX |
.------------.
| N1 | 5 |
| N2 | 8 |
.____________.
I just want the rows, grouped by Name but just the newest ones. I dont want the row with XX=10 in this example because the date 2009-05-01 > 2008-01-08.
I don't know how to sort by Date and group it :(

What do you want the grouping for?
select Name, XX
from yourTable t1
where Date = (select MAX(Date)
from yourTable t2
where t1.Name = t2.Name)
If you need to sum XX for the last day, then:
select Name, SUM(XX)
from yourTable t1
where Date = (select MAX(Date)
from yourTable t2
where t1.Name = t2.Name)
group by Name

SELECT Name, XX FROM myTable GROUP BY Name ORDER BY Date DESC
You may need to put quotes around your date field
`Date`

Sorry but these 2 are both wrong.
You should
SELECT Name, XX
FROM t1
JOIN (SELECT Name, max(date)
FROM t1
GROUP BY Name) subquery
ON t1.Name = subquery.Name AND t1.Date = subquery.Date

Related

Tie-breaking mutliple matches on MAX() in SQL

I have a table that looks like this:
| client_id | program_id | provider_id | date_of_service | data_entry_date | data_entry_time |
| --------- | ---------- | ----------- | --------------- | --------------- | --------------- |
| 2 | 5 | 6 | 02/02/2022 | 02/02/2022 | 0945 |
| 2 | 5 | 6 | 02/02/2022 | 02/07/2022 | 0900 |
| 2 | 5 | 6 | 02/04/2022 | 02/04/2022 | 1000 |
| 2 | 5 | 6 | 02/04/2022 | 02/04/2022 | 1700 |
| 2 | 5 | 6 | 02/04/2022 | 02/05/2022 | 0800 |
| 2 | 5 | 6 | 02/04/2022 | 02/05/2022 | 0900 |
I need to get the most recent date_of_service entered. From the table above, the desired result/row is:
date_of_service = 02/04/2022, data_entry_date = 02/05/2022, data_entry_time = 0900
This resulting date_of_service will be left joined to the master table.
This query mostly works:
SELECT t1.client_id, t1.program_id, t1.provider_id, t2.date_of_service
FROM table1 as t1
WHERE provider_id = '6'
LEFT JOIN
(SELECT client_id, program_id, provider_id, date_of_service
FROM table2) as t2
ON t2.client_id = t1.client_id
AND t2.program_id = t1.program_id
AND t2.provider_id = t1.provider_id
AND t2.date_of_service =
(SELECT MAX(date_of_service)
FROM t2 as t3
WHERE t3.client_id = t1.client_id
AND t3.program_id = t1.program_id
AND t3.provider_id = t1.provider_id
)
)
But it also returns multiple rows whenever there is more than one match on the max(date_of_service).
To solve this, I need to use the max data_entry_date to break any ties whenever there is more than one row that matches the max(date_of_service). Likewise, I also need to use the max data_entry_time to break any ties whenever there is more than one row that also matches the max data_entry_date.
I tried the following:
SELECT t1.client_id, t1.program_id, t1.provider_id, t2.date_of_service
FROM table1 as t1
WHERE provider_id = '6'
LEFT JOIN
(SELECT TOP(1) client_id, program_id, provider_id, date_of_service, data_entry_date, data_entry_time
FROM table2
ORDER BY date_of_service DESC, data_entry_date DESC, data_entry_time DESC
) as t2
ON t2.client_id = t1.client_id
AND t2.program_id = t1.program_id
AND t2.provider_id = t1.provider_id
But I can only get it to return null values for the date_of_service.
Likewise, this:
SELECT t1.client_id, t1.program_id, t1.provider_id, t2.date_of_service
FROM table1 as t1
WHERE provider_id = '6'
LEFT JOIN
(
SELECT TOP(1) client_id AS client_id2, program_id AS program_id2, provider_id AS provider_id2, date_of_service, data_entry_date, data_entry_time
FROM table2 AS t3
JOIN
(SELECT
MAX(date_of_service) AS max_date_of_service
,MAX(data_entry_date) AS max_data_entry_date
FROM table1
WHERE date_of_service = (SELECT MAX(date_of_service) FROM table2)
) AS t4
ON t3.date_of_service = t4.max_date_of_service
AND t3.data_entry_date = t4.max_data_entry_date
ORDER BY data_entry_time
) AS t2
ON t2.client_id2 = t1.client_id
AND t2.program_id2 = t1.program_id
AND t2.provider_id2 = t1.provider_id
... works (meaning it doesn't throw any errors), but it only seems to return null values for me.
I've tried various combinations of MAX, ORDER BY, and multiple variations of JOIN's, but haven't found one that works yet.
I don't know what version my SQL database is, but it doesn't appear to handle window functions like OVER and PARTITION or other things like COALESCE. I've been using DBeaver 22.2.0 to test the SQL scripts.
Based on your what you've provided, looks like you can simply query table2:
SELECT client_id, program_id, provider_id, MAX(date_of_service), MAX(data_entry_date), MAX(data_entry_time)
FROM table2
GROUP BY client_id, program_id, provider_id
If you need to join this result set to table1, just JOIN to the statement above on client_id, program_id, provider_id
Try using below query. This is using just joins and sub query.
SELECT TOP 1 * FROM table1 t1
JOIN (
SELECT
MAX(date_of_Service) AS Max_date_of_Service
,MAX(data_entry_date) AS Max_data_entry_date
FROM table1
WHERE date_of_Service = (SELECT MAX(date_of_Service) FROM table1)
)t2
ON t1.date_of_Service = t2.Max_date_of_Service
AND t1.data_entry_date = t2.Max_data_entry_date
ORDER BY data_entry_time

pulling rows with a max(column) value but with regards to being smaller than another column in SQL

I have two different data sets but I want to append the columns of one onto the other based on it's date being the max date that is STILL less than the date in the other dataset in SQL.
Example Table 1)
| ID | date | value |
| 05 | 10/13 | ab |
| 10 | 10/15 | sd |
Example Table 2)
| ID2 | date2 | value2 |
| 05 | 10/10 | rf |
| 05 | 10/23 | tx |
| 10 | 10/01 | jk |
| 10 | 10/12 | fr |
| 10 | 10/23 | as |
And the resulting table I want is:
| ID | date | value | date2 | value2 |
| 05 | 10/13 | ab | 10/10 | rf |
| 10 | 10/15 | sd | 10/12 | fr |
When I try to code it, I can't seem to get the correct result. I have tried something like this but I get an error:
select
t1.*
into final
from table1 t1
left join
(select
ID2,
date2,
value2
from
table2
Where max(date2 < date)) AS t2
on t1.ID = t2.ID2;
As noted in the comments, you don't have dates in your sample data. If we pretend you indeed have dates such as those found in this fiddle, then the following could work where CTEs are used.
with max_date as (
select t2.id, max(t2.date) as max_t2_date
from table2 t2
join table1 t1
on t2.id = t1.id
where t2.date < t1.date
group by t2.id
),
max_date_value as (
select t2.id, t2.value, mm.max_t2_date
from table2 t2
join max_date mm
on t2.id = mm.id
and t2.date = mm.max_t2_date
)
select t1.id, t1.date, t1.value, mdv.max_t2_date as date2, mdv.value as value2
from table1 t1
left join max_date_value mdv
on t1.id = mdv.id
Output:
id
date
value
date2
value2
05
2021-10-13T00:00:00.000Z
ab
2021-10-10T00:00:00.000Z
rf
10
2021-10-15T00:00:00.000Z
sd
2021-10-12T00:00:00.000Z
fr
There are likely shorter ways to achieve this but knowing the RDBMS is required. This could at least get you started and play around with different methods.
Assuming that the date and date2 columns are of the type CHAR(5) and stores values like MM/DD, to get the expected results you can use a query like this
WITH t2_rn AS (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY id2 ORDER BY date2 DESC) AS rn2
FROM table2
WHERE EXISTS (
SELECT 1 FROM table1
WHERE id = id2 AND date > date2
)
)
SELECT
id,
date,
value,
date2,
value2
FROM table1
LEFT JOIN t2_rn ON id = id2 AND rn2 = 1
If you are using SQL Server then you you can use the OUTER APPLY operator, and the query will look like this
SELECT
id,
date,
value,
date2,
value2
FROM table1
OUTER APPLY (
SELECT TOP 1
date2,
value2
FROM table2
WHERE id = id2 AND date > date2 ORDER BY date2 DESC
) t2
Both queries have the same output
id
date
value
date2
value2
5
10/13
ab
10/10
rf
10
10/15
sd
10/12
fr
You can check a working demo with both queries here

Select row with max value saving distinct column

I have values
- id|type|Status|Comment
- 1 | P | 1 | AAA
- 2 | P | 2 | BBB
- 3 | P | 3 | CCC
- 4 | S | 1 | DDD
- 5 | S | 2 | EEE
I wan to get values for each type with max status and with comment from the row with max status:
- id|type|Status|Comment
- 3 | P | 3 | CCC
- 5 | S | 2 | EEE
All the existing questions on SO do not care about the right correspondence of Max type and value.
This gives you one row per type, which have max status
select * from (
select your_table.*, row_number() over(partition by type order by Status desc) as rn from your_table
) tt
where rn = 1
Corrected: The below will use a subquery to figure out each type and what the max status is, then it joins that onto the original table and uses the where clause to only select those rows where the status equals the max status. Of note, if you have multiple records with the same max status, you will get both of them to come up.
WITH T1 AS (SELECT type, MAX(STATUS) AS max_status FROM table_name GROUP BY type)
SELECT t2.id, t2.type, t2.status, t2.comment
FROM T1 LEFT JOIN table_name t2 ON t2.type= T1.type
WHERE t2.status = T1.max_status

postgresql - How to get one row the min value

I have table (t_image) with this column
datacd | imagecode | indexdate
----------------------------------
A | 1 | 20170213
A | 2 | 20170213
A | 3 | 20170214
B | 4 | 20170201
B | 5 | 20170202
desired result is this
datacd | imagecode | indexdate
----------------------------------
A | 1 | 20170213
B | 4 | 20170201
In the above table, I want to retrieve 1 row for each datacd who has the minimum index date
Here is my query, but the result returns 2 rows for datacd A
select *
from (
select datacd, min(indexdate) as indexdate
from t_image
group by datacd
) as t1 inner join t_image as t2 on t2.datacd = t1.datacd and t2.indexdate = t1.indexdate;
The Postgres proprietary distinct on () operator is typically the fastest solution for greatest-n-per-group queries:
select distinct on (datacd) *
from t_image
order by datacd, indexdate;
One option uses ROW_NUMBER():
SELECT t.datacd,
t.imagecode,
t.indexdate
FROM
(
SELECT datacd, imagecode, indexdate,
ROW_NUMBER() OVER (PARTITION BY datacd ORDER BY indexdate) rn
FROM t_image
) t
WHERE t.rn = 1

how to query range?

Raw Data
| ID | STATUS |
| 1 | A |
| 2 | A |
| 3 | B |
| 4 | B |
| 5 | B |
| 6 | A |
| 7 | A |
| 8 | A |
| 9 | C |
Result
| START | END |
| 1 | 2 |
| 6 | 8 |
Range of STATUS A
How to query ?
This should give you the correct ranges:
SELECT
STATUS,
MIN(ID),
max_id
FROM (
SELECT
t1.STATUS,
t1.ID,
COALESCE(MAX(t2.ID), t1.ID) max_id
FROM
yourtable t1 LEFT JOIN yourtable t2
ON t1.STATUS=t2.STATUS AND t1.ID<t2.ID
WHERE
NOT EXISTS (SELECT NULL
FROM yourtable t3
WHERE
t3.STATUS!=t1.STATUS
AND t3.ID>t1.ID AND t3.ID<t2.ID)
GROUP BY
t1.ID,
t1.STATUS
) s
WHERE
status = 'A'
GROUP BY
STATUS,
max_id
Please see fiddle here.
You are probably better off with a cursor-based solution or a client-side function.
However, if you were using Oracle - the following would work.
WITH LOWER_VALS AS
( -- All the Ids with no immediate predecessor
SELECT ROWNUM AS RN, STATUS, ID AS LOWER FROM
(
SELECT STATUS, ID
FROM RAWDATA RD1
WHERE RD1.ID -1 NOT IN
(SELECT ID FROM RAWDATA PRED_TABLE WHERE PRED_TABLE.STATUS = RD1.STATUS)
ORDER BY STATUS, ID
)
) ,
UPPER_VALS AS
( -- All the Ids with no immediate successor
SELECT ROWNUM AS RN, STATUS, ID AS UPPER FROM
(
SELECT STATUS, ID
FROM RAWDATA RD2
WHERE RD2.ID +1 NOT IN
(SELECT ID FROM RAWDATA SUCC_TABLE WHERE SUCC_TABLE.STATUS = RD2.STATUS)
ORDER BY STATUS, ID
)
)
SELECT
L.STATUS, L.LOWER, U.UPPER
FROM
LOWER_VALS L
JOIN UPPER_VALS U ON
U.RN = L.RN;
Results in the set
A 1 2
A 6 8
B 3 5
C 9 9
http://sqlfiddle.com/#!4/10184/2
There is not a lot to go on from what you put, but I think this might work. I am using T-SQL because I don't know what you are using?
SELECT
min(ID)
, max(ID)
FROM RawData
WHERE [Status] = 'A'