How to get max value from sql table with group by? - sql

I have a table
Id | Version | DateFrom | DateTo |
_______________________________________
1 | 1 | 2015-09-15 | 2015-09-18 |
1 | 2 | 2015-09-15 | 2015-09-18 |
1 | 3 | 2015-09-15 | 2015-09-20 | --different date
1 | 4 | 2015-09-15 | 2015-09-18 |
2 | 1 | 2015-09-15 | 2015-09-18 |
2 | 2 | 2015-09-15 | 2015-09-18 |
And I'm trying to make a view which return records with the lastest version independently from the rest of the columns.
So for example I expect:
Id | Version | DateFrom | DateTo |
_______________________________________
1 | 4 | 2015-09-15 | 2015-09-18 |
2 | 2 | 2015-09-15 | 2015-09-18 |
This is what I already did:
Select
Id,
MAX([Version]) AS Version,
DateFrom,
DateTo
FROM
dbo.Table_1
Group By
Id,
DateFrom,
DateTo
But the result is:
Id | Version | DateFrom | DateTo |
_______________________________________
1 | 4 | 2015-09-15 | 2015-09-18 |
1 | 3 | 2015-09-15 | 2015-09-20 |
2 | 2 | 2015-09-15 | 2015-09-18 |

Can also be done with a left join :
SELECT t.*
FROM YourTable t
LEFT JOIN YourTable s
ON(t.id = s.id AND t.version < s.version)
WHERE s.version is null

Have a sub-query that returns each id's max version. Join with that result:
select t1.*
from tablename t1
join (select id, max(version) as maxversion
from tablename
group by id) t2
on t1.id = t2.id and t1.version = t2.maxversion

You can run that kind of query :
Select ID, version, dateFrom, dateTo
from table_1 a
where not exists (
select 1
from table_1 b
where a.id = b.id and a.version < b.version)

Related

Select most recent inspection

I have a ROAD_INSPECTION table:
+----+------------------------+-----------+
| ID | DATE | CONDITION |
+----+------------------------+-----------+
| 1 | 01/01/2009 | 20 |
| 1 | 05/01/2013 | 16 |
| 1 | 04/29/2016 10:02:52 AM | 15 |
+----+------------------------+-----------+
| 2 | 01/01/2009 | 8 |
| 2 | 06/06/2012 9:55:13 AM | 8 |
| 2 | 04/28/2015 | 11 |
+----+------------------------+-----------+
| 3 | 06/11/2012 | 10 |
| 3 | 04/21/2015 | 19 |
+----+------------------------+-----------+
What is the most efficient way to select the most recent inspection? The query would need to include the ID and CONDITION columns, despite the fact that they wouldn't group by cleanly:
+----+------------------------+-----------+
| ID | DATE | CONDITION |
+----+------------------------+-----------+
| 1 | 04/29/2016 10:02:52 AM | 15 |
+----+------------------------+-----------+
| 2 | 04/28/2015 | 11 |
+----+------------------------+-----------+
| 3 | 04/21/2015 | 19 |
+----+------------------------+-----------+
One way could be to retrieve id and date column in derived table and join the output to the main table to retrieve corresponding data from condition column as below.
SELECT t1.id,
t1.date1,
t2.CONDITION1
FROM
(SELECT id,
max(date1) AS date1
FROM table1
GROUP BY id) t1
JOIN table1 t2 ON t1.id = t2.id
AND t1.date1 = t2.date1;
Result:
id date1 CONDITION1
-------------------------------------
1 29.04.2016 10:02:52 15
2 28.04.2015 00:00:00 11
3 21.04.2015 00:00:00 19
DEMO
OR if your rdbms supports windows function, use below.
SELECT id,
date1,
condition1
FROM
(SELECT id,
date1,
condition1,
row_number() over(PARTITION BY id
ORDER BY date1 DESC) AS rn
FROM table1 ) t1
WHERE rn = 1;
DEMO

How to query two tables grouping by date and counting date registries for each table

I am using Firebird 2.5 and I have two tables:
|----------TABLE_1---------| |----------TABLE_2---------|
| DATE_1 | SOME_INFO_1 | | DATE_2 | SOME_INFO_2 |
| 2015-05-01 | Brazil | | 2015-04-10 | Bread |
| 2015-06-23 | Paraguai | | 2015-05-01 | Air |
| 2015-05-01 | Chile | | 2015-05-01 | Water |
| 2015-05-01 | Argentina |
I want to group this tables by date, in such way that I can count how much registries I have per date in each table. This is the expected result:
|----------------RESULT_TABLE----------------|
| DATE | COUNT_TABLE_1 | COUNT_TABLE 2 |
| 2014-04-10 | 0 | 1 |
| 2015-05-01 | 3 | 2 |
| 2015-06-23 | 1 | 0 |
I am trying this:
SELECT
a.date_1,
COUNT(a.date_1) AS count_table_1,
COUNT(b.date_2) AS count_table_2
FROM
table_1 a
LEFT OUTER JOIN
table_2 b ON b.date_2 = a.date_1
GROUP BY
a.date_1, b.date_2
ORDER BY
a.date_1 ASC, b.date_2 ASC
And I am getting this as result:
|----------------RESULT_TABLE----------------|
| DATE | COUNT_TABLE_1 | COUNT_TABLE 2 |
| 2014-04-10 | 0 | 1 |
| 2015-05-01 | 6 | 6 |
| 2015-06-23 | 1 | 0 |
I am feeling that my SQL is a mess, but I can't solve it.
First, aggregate the results in each table and then join using the date column.
select t1.date_1 as dt, isnull(t1_count,0), isnull(t2_count,0)
from
(SELECT date_1, count(*) as t1_count from table_1 group by date_1) t1
full outer join
(SELECT date_2, count(*) as t2_count from table_2 group by date_2) t2
on t1.date_1 = t2.date_2

Update using Self Join Sql Server

I have huge data and sample of the table looks like below
+-----------+------------+-----------+-----------+
| Unique_ID | Date | RowNumber | Flag_Date |
+-----------+------------+-----------+-----------+
| 1 | 6/3/2014 | 1 | 6/3/2014 |
| 1 | 5/22/2015 | 2 | NULL |
| 1 | 6/3/2015 | 3 | NULL |
| 1 | 11/20/2015 | 4 | NULL |
| 2 | 2/25/2014 | 1 | 2/25/2014 |
| 2 | 7/31/2014 | 2 | NULL |
| 2 | 8/26/2014 | 3 | NULL |
+-----------+------------+-----------+-----------+
Now I need to check if the difference between Date in 2nd row and Flag_date in 1st row. If the difference is more than 180 then 2nd row Flag_date should be updated with the date in 2nd row else it needs to be updated by Flag_date in 1st Row. And same rule follows for all rows with same unique_ID
update a
set a.Flag_Date=case when DATEDIFF(dd,b.Flag_Date,a.[Date])>180 then a.[Date] else b.Flag_Date end
from Table1 a
inner join Table1 b
on a.RowNumber=b.RowNumber+1 and a.Unique_ID=b.Unique_ID
The above update query when executed once, only the second row under each Unique_ID gets updated and result looks like below
+-----------+------------+-----------+------------+
| Unique_ID | Date | RowNumber | Flag_Date |
+-----------+------------+-----------+------------+
| 1 | 2014-06-03 | 1 | 2014-06-03 |
| 1 | 2015-05-22 | 2 | 2015-05-22 |
| 1 | 2015-06-03 | 3 | NULL |
| 1 | 2015-11-20 | 4 | NULL |
| 2 | 2014-02-25 | 1 | 2014-02-25 |
| 2 | 2014-07-31 | 2 | 2014-02-25 |
| 2 | 2014-08-26 | 3 | NULL |
+-----------+------------+-----------+------------+
And I need to run four times to achieve my desired result
+-----------+------------+-----------+------------+
| Unique_ID | Date | RowNumber | Flag_Date |
+-----------+------------+-----------+------------+
| 1 | 2014-06-03 | 1 | 2014-06-03 |
| 1 | 2015-05-22 | 2 | 2015-05-22 |
| 1 | 2015-06-03 | 3 | 2015-05-22 |
| 1 | 2015-11-20 | 4 | 2015-11-20 |
| 2 | 2014-02-25 | 1 | 2014-02-25 |
| 2 | 2014-07-31 | 2 | 2014-02-25 |
| 2 | 2014-08-26 | 3 | 2014-08-26 |
+-----------+------------+-----------+------------+
Is there a way where I can run update only once and all the rows are updated.
Thank you!
If you are using SQL Server 2012+, then you can use lag():
with toupdate as (
select t1.*,
lag(flag_date) over (partition by unique_id order by rownumber) as prev_flag_date
from table1 t1
)
update toupdate
set Flag_Date = (case when DATEDIFF(day, prev_Flag_Date, toupdate.[Date]) > 180
then toupdate.[Date] else prev_Flag_Date
end);
Both this version and your version can take advantage of an index on table1(unique_id, rownumber) or, better yet, table1(unique_id, rownumber, flag_date).
EDIT:
In earlier versions, this might have better performance:
with toupdate as (
select t1.*, t2.flag_date as prev_flag_date
from table1 t1 outer apply
(select top 1 t2.flag_date
from table1 t2
where t2.unique_id = t1.unique_id and
t2.rownumber < t1.rownumber
order by t2.rownumber desc
) t2
)
update toupdate
set Flag_Date = (case when DATEDIFF(day, prev_Flag_Date, toupdate.[Date]) > 180
then toupdate.[Date] else prev_Flag_Date
end);
The CTE can make use of the same index -- and it is important to have the index. The reason for the better performance is because your join on row_number() cannot use an index on that field.

SQL Query to get results that match between three tables, or a single result for no match

Is there a way to use a where clause to check if there were zero matches between tables for a record from the first table, and produce one row or results reflecting that?
I'm trying to get results that look like this:
+----------+----------+-----------+----------+-------------+
| Results |
+----------+----------+-----------+----------+-------------+
| Date | Queue ID | From Date | To Date | Campaign ID |
| 3/1/2014 | 1 | 2/24/2014 | 3/2/2014 | 1 |
| 3/1/2014 | 2 | (NULL) | (NULL) | (NULL) |
+----------+----------+-----------+----------+-------------+
From a combination of tables that look like this:
+----------+-------+ +-------+----+ +----+-----------+-----------+----------+
| Table 1 | | Table 2 | | Table 3 |
+----------+-------+ +-------+----+ +----+-----------+-----------+----------+
| Date | Queue | | Queue | SP | | SP | From Date | To Date | Campaign |
| | ID | | ID | ID | | ID | | | ID |
+----------+-------+ +-------+----+ +----+-----------+-----------+----------+
| 3/1/2014 | 1 | | 1 | 1 | | 1 | 2/24/2014 | 3/2/2014 | 1 |
| 3/1/2014 | 2 | | 1 | 2 | | 2 | 3/3/2014 | 3/9/2014 | 5 |
| | | | 1 | 3 | | 3 | 3/10/2014 | 3/16/2014 | 1 |
| | | | 1 | 4 | | 4 | 3/17/2014 | 3/23/2014 | 1 |
| | | | 1 | 5 | | 5 | 3/24/2014 | 3/30/2014 | 4 |
| | | | 2 | 6 | | 6 | 3/3/2014 | 3/9/2014 | 5 |
| | | | 2 | 7 | | 7 | 3/10/2014 | 3/16/2014 | 5 |
| | | | 2 | 8 | | 8 | 3/17/2014 | 3/23/2014 | 5 |
| | | | 2 | 9 | | 9 | 3/24/2014 | 3/30/2014 | 5 |
+----------+-------+ +-------+----+ +----+-----------+-----------+----------+
I'm joining Table 1 to Table 2 on QUEUE ID,
and Table 2 to Table 3 on SP ID,
and DATE from Table 1 should fall between Table 3's FROM DATE and TO DATE.
I want a single record returned for each queue, including if there were no date matches.
Unfortunately any combinations of joins or where clauses I've tried so far only result in either one record for Queue ID 1 or multiple records for each Queue ID.
I would suggest this:
SELECT
t1.Date,
t1.QueueID,
s.FromDate,
s.ToDate,
s.CampaignID
FROM
Table1 t1
LEFT JOIN
(
SELECT
t2.QueueID,
t3.FromDate,
t3.ToDate,
t3.CampaignID
FROM
Table2 t2
INNER JOIN
Table3 t3 ON
t2.SPID = t3.SPID
) s ON
t1.QueueID = s.QueueID AND
t1.Date BETWEEN s.FromDate AND s.ToDate
SQL Fiddle here with an abbreviated dataset
A trivial amendment to AHiggins code. Using the CTE makes it a little easier to read perhaps.
With AllDates as
(
SELECT
t2.QueueID,
t3.FromDate,
t3.ToDate,
t3.CampaignID
FROM Table2 t2
INNER JOIN Table3 t3 ON
t2.SPID = t3.SPID
)
SELECT
t1.Date,
t1.QueueID,
s.FromDate,
s.ToDate,
s.CampaignID
FROM Table1 t1
LEFT JOIN AllDates s ON
t1.QueueID = s.QueueID AND
t1.Date BETWEEN s.FromDate AND s.ToDate
You want something like:
select distinct t1.date, t1,queue_id IFNULL(t3.from_date,'NULL'),
IFNULL(t3.to_date,'NULL'), IFNULL(t3.campaign,'NULL')
FROM table1 t1
LEFT OUTER JOIN table2 t2 on t1.queue_id = t2.queue_id
left outer join table3 t3 on t2.sp_id = t3.sp_id
where t3.from_date <= t1.date
AND t3.to_date >= t1.date
This will select dsitinct records from the table (eliminating null duplicates and replacing them with NULL)
SELECT t1.[Date], t1.[Queue ID], s.[From Date], s.[To Date], s.[Campaign ID]
FROM table1 t1
LEFT JOIN (SELECT t3.*, t2.[Queue ID] FROM table3 t3 JOIN table2 t2 ON t2.[SP ID] = t3.[SP ID]) s
ON s.[Queue ID] = t1.[Queue ID] AND t1.[Date] BETWEEN s.[From Date] AND s.[To Date]
SQL Fiddle

SQL "Group By" VarChar Field With Max Date or All results of the same date

Lets say I have this table
--------------------------------------------------------------
| ID | DATE | GROUPNAME | RESULT | INFO1 | INFO2 |
--------------------------------------------------------------
| 1 | 01/06 | Group1 | 12345 | Abc | xxxx |
| 2 | 01/04 | Group2 | 54321 | AAA | zzzz |
| 3 | 01/03 | Group3 | 11111 | BBB | zzzz |
| 4 | 01/06 | Group1 | 22222 | Def | xxxx |
| 5 | 01/02 | Group3 | 33333 | CCC | yyyy |
--------------------------------------------------------------
I want to make a query that selects the max date of each groupname and return all results of that date from that groupname. And order by the groupname
E.g., My result would be
1 | 01/06 | Group1 | 12345 | Abc | xxxx
4 | 01/06 | Group1 | 22222 | Def | xxxx
2 | 01/04 | Group2 | 54321 | AAA | zzzz
3 | 01/03 | Group3 | 11111 | BBB | zzzz
What would be an efficient query to produce that result set?
Thank you!
Unless I'm missing something:
SELECT t.id,
t.date,
t.groupname,
t.result,
t.info1,
t.info2
FROM TABLE t
JOIN (SELECT t.groupname,
MAX(t.date) 'maxd'
FROM TABLE t
GROUP BY t.groupname) x ON x.groupname = t.groupname
AND x.maxd = t.date
ORDER BY t.groupname
SELECT TABLE.ID, TABLE.DATE, TABLE.GROUPNAME, TABLE.RESULT, TABLE.INFO1, TABLE.INFO2
FROM TABLE INNER JOIN (SELECT GROUPNAME, MAX(DATE) FROM TABLE GROUP BY GROUPNAME) T
ON TABLE.GROUPNAME = T.GROUPNAME AND TABLE.DATE = T.DATE
ORDER BY TABLE.GROUPNAME
try this:
Width (
Select max(Date), groupname
from Table
group gy groupname
) AS T1
Select T2.id,
T2.Date,
T2.groupname,
T2.result,
T2.info1,
T2.info2
from T1
left join Table T2
on (T1.date = T2.date
AND T1.groupname = T2.groupname)
order by groupname