SQL Select where first value and last value of daterange - sql

I'm new to SQL queries and I need to make a join starting from this query:
SELECT b.Name, a.*
FROM a INNER JOIN b ON a.VId = b.Id
WHERE b.SId = 100
AND a.Day >= '2016-05-05'
AND a.Day < '2016-05-09';
and adding 2 more columns to the first selected data (SCap and ECap from table c).
From what I've tried my code looks like this:
SELECT b.Name,a.*,
c.MaxDay,
c.Cap,
FROM a INNER JOIN b
ON a.VId = b.Id
INNER JOIN
(SELECT VId,
MAX(TimestampLocal) AS MaxDay,
CAST (TimestampLocal AS DATE) AS Day,
Cap,
FROM Info
GROUP BY VId,
CAST (TimestampLocal AS DATE),
Cap) AS c
ON a.VId = c.VId
AND a.Day = c.Day
WHERE b.SId = 33
AND a.Day >= '2016-05-05'
AND a.Day < '2016-05-09';
But I get more rows than needed.
I need the earliest and the latest TimestampLocal for a given vehicle in a daterange. That would come from two records in Info, and each would have its proper values for Cap.
For example:
I have two Names with values inside table Info for 2 days (Name 1) and only one day for Name 2:
- Day 1 2016-05-07:
- Name 1: Values at 2:45, 10:10 and 3.10
- Name 2: Values at 5:13 and 8:22
- Day 2 2016-05-09:
- Name 1: Values at 4:13, 6:15 and 9:20
I need to display (if I select daterange: 2016-05-05 to 2016-05-09) for Name 1 for SCap the value from 2016-05-07 from 2:45 and for ECap the value from 2016-05-09 from 9:20 and for Name 2 for SCap the value from 2016-05-07 from 5:13 and for ECap the value from 2016-05-07 from 8:22. This should be displayed in 2 lines.
Is there a way I can add those 2 columns into my query without adding more rows for the same Name?
EDIT!
Table a I have:
VId | Day
5251 | 05/09/2016
5382 | 05/09/2016
Table b:
Id | Name
5251 | N1
5382 | N2
Table Info:
VId | TimestampLocal | Cap
5251 | 2016-05-09 11:33:46.2000000 +03:00 | 0
5251 | 2016-05-09 11:37:11.4000000 +03:00 | 7
5251 | 2016-05-09 11:38:11.4000000 +03:00 | 4
5251 | 2016-05-09 11:39:11.7000000 +03:00 | 2
5382 | 2016-05-09 09:30:56.6000000 -04:00 | 5
5382 | 2016-05-09 09:31:56.6000000 -04:00 | 3
And I need to display - if I select a daterange from 2016-05-03 to 2016-05-10:
Id | Name | SCap | ECap
5251 | N1 | 0 | 2
5382 | N2 | 5 | 3

You can use a CTE with ROW_NUMBER in order to retrieve the two records:
;WITH Info_CTE AS (
SELECT VId,
CAST (TimestampLocal AS DATE) AS Day,
Cap,
ROW_NUMBER() OVER (PARTITION BY VId
ORDER BY TimestampLocal) AS rn1,
ROW_NUMBER() OVER (PARTITION BY VId
ORDER BY TimestampLocal DESC) AS rn2
FROM Info
)
SELECT b.Name,
a.*,
c.Day,
c.Cap
FROM a
INNER JOIN b ON a.VId = b.Id
INNER JOIN Info_CTE AS c ON a.VId = c.VId AND
a.Day = c.Day AND
1 IN (c.rn1, c.rn2)
WHERE b.SId = 33
AND a.Day >= '2016-05-05'
AND a.Day < '2016-05-09';
If you want ECap and SCap as separate columns then instead of
c.Cap
you can use:
CASE WHEN c.rn1 = 1 THEN c.Cap END AS ECap,
CASE WHEN c.rn2 = 1 THEN c.Cap END AS SCap

First, get the max and min timestamp for each id for a given date. Then join it twice, once with the max timestamp value and then with the min timestamp value for each id to tblinfo,to get the start and end cap values for those rows.
Add a where clause with a date filter to filter for specific days.
Sample demo
with maxandmin as
(select vid
,max(timestamplocal) maxtime
,min(timestamplocal) mintime
from tblinfo
group by vid,cast(timestamplocal as date))
select m.vid,b.name,i1.cap as Scap,i2.cap as Ecap
from maxandmin m
join tblinfo i1 on m.vid=i1.vid and m.mintime = i1.timestamplocal
join tblinfo i2 on m.vid=i2.vid and m.maxtime = i2.timestamplocal
join tableb b on b.id=m.vid

I found a solution for my query after some further investigations and here is what I managed to do:
SELECT b.Id,
b.Name,
c.S_Time,
c.E_Time,
s.Cap AS S_Cap,
e.Capa AS E_Cap,
FROM b
INNER JOIN (SELECT VId,
MIN(TimestampLocal) AS S_Time,
MAX(TimestampLocal) AS E_Time
FROM Info
where CAST (TimestampLocal AS DATE) >='2016-04-05'
and CAST (TimestampLocal AS DATE) <'2016-05-10'
GROUP BY VId
) AS c
ON b.Id = c.VId
INNER JOIN Info AS s
ON s.VId = c.VId
AND s.TimestampLocal = c.S_Time
INNER JOIN Info AS e
ON e.Vd = c.VId
AND e.TimestampLocal = c.E_Time
WHERE b.SId = 100

Related

Write Sql script to fetch data in one to many relationship

I want to write a sql script which fetches data from 2 tables one is parent and second is child table
Bid
BidId | Code | Date
1 | H | 2022-05-12
2 | B | 2022-05-13
BidResult
BidResultId | BidId | Emi
12 | 1 | 50
13 | 1 | 20
14 | 2 | 30
Bid and BidResult
i want fetch column Date,Code,BidId from Bid Table
and BidResultId, EMI from BidResult but want a another column of Minimum EMI
from above example i want to fetch for bidId 1
Code H,date 2022-05-12,BidResultId 12, Emi 50 and Min Emi between 50 and 20 which is 20
so i have written following query
Select B.BidId,BR.EMI As Installment,
(Select Min(BR.EMI ) from BidResult BR
Inner Join Bid B on B.BidId = BR.BidResultId
where B.BidId = 5) As MinInstallment,
B.Code,
BR.BidResultId,
CONVERT(DATE, B.Date) As BidDate
from Bid B
Inner Join BidResult BR On B.BidId = BR.BidId
where B.BidId= 5 and B.TypeId = 1
All Field are starightforward except the minimum EMI value from BidResult for that BidId
please check the query and suggest if any modifications
Solution 1: With group by
select BID, min(EMI) EMI
into #temp
from BIDResult
group by BID
select b.Date, b.Code, b.BidId, br.BidResultId, br.EMI
from BID b
inner join #temp on t.BID = b.BID
inner join BIDResult br on br.BID = t.BID and br.EMI = t.EMI
Solution 2: Without group by
select *, ROW_Number() over(PARTITION by BID order by EMI) RowNumber
into #temp
from BIDResult
select b.Date, b.Code, b.BidId, br.BidResultId, br.EMI
from BID b
inner join #temp t on t.BID = b.BID and t.RowNumber = 1

sql query to get max date from multiple columns of multiple table in db2

I have multiple tables having date_modified column, and I need to create a view using all these tables but date_modified should be max of date_modified of these tables.
table1
id vendor_number fiscal_year date_created date_modified
1 124 2021 2021/11/01 2021/11/02
2 231 2021 2021/11/01 2021/11/03
3 232 2021 2021/11/02 NULL
4 234 2021 2021/11/02 NULL
table2
id fiscal_year discount_amt date_created date_modified
1 2021 10.30 2021/11/01 2021/11/03
2 2021 15.23 2021/11/01 2021/11/02
3 2021 17.45 2021/11/02 2021/11/02
4 2021 18.49 2021/11/02 NULL
table3
id vendor_number date_created date_modified
1 124 2021/11/01 2021/11/04
2 231 2021/11/01 2021/11/01
3 232 2021/11/01 2021/11/03
4 234 2021/11/02 2021/11/03
Required Output :
id|fiscal_year|discount_amt|vendor_number|date_created|date_modified
1 | 2021 | 10.30 | 124 | 2021/11/01 | 2021/11/04
2 | 2021 | 15.23 | 231 | 2021/11/01 | 2021/11/03
3 | 2021 | 17.45 | 232 | 2021/11/02 | 2021/11/03
4 | 2021 | 18.49 | 234 | 2021/11/02 | 2021/11/03
VIEW SQL:
CREATE VIEW view_data
AS
SELECT T1.id, T1.fiscal_year, T2.discount_amt, T3.vendor_number, T1.date_created, max(multiple date_modified columns..from multiple tables..)
FROM table1 AS T1
LEFT JOIN table2 AS T2
ON T1.id = T2.id
LEFT JOIN T3 v
ON T1.vendor_number = T3.vendor_number;
Assuming the id columns are keys of each table you can join them (using full outer join maybe) and then use GREATEST() to get the latest date.
For example:
create view v as
select
coalesce(a.id, b.id, c.id) as id,
b.fiscal_year,
b.discount_amt,
a.date_created,
greatest(a.date_modified, b.date_modified, c.date_modified) as date_modified
from table1 a
full join table2 b on b.id = a.id
full join table3 c on c.id = b.id or c.id = a.id
EDIT: If your version of DB2 doesn't implement GREATEST() you can replace it with the [rather long] CASE clause:
case when a.date_modified > b.date_modified then
case when a.date_modified > c.date_modified
then a.date_modified else c.date_modified end
else
case when b.date_modified > c.date_modified
then b.date_modified else c.date_modified end
end
Alternatively, you can implement the function yourself. It's pretty straightforward. For example:
create function greatest(in a date, in b date) returns date
language sql
begin
if a > b then return a; end if;
return b;
end
//
See running example of this custom function at db<>fiddle 1.
EDIT #2: Dealing with nulls
Nulls are not values, and the behavior of the database is correct. In the presence of an unknown date the engine cannot determine which date is greater and returns UNKNOWN -- in the form of a null.
Now, if you want nulls to behave as in programming languages like C, Java, PHP, then you can either 1) Use a lot of CASE/COALESCE clauses or you can simply modify your custom function to wotk as you please. Below is an example of the modified custom function:
create function mygreatest(in a date, in b date) returns date
language sql
begin
if a is null then return b; end if;
if b is null then return a; end if;
if a > b then return a; end if;
return b;
end
Then, you can see it in action:
with data (x, y) as (
select date '2021-07-01', date '2021-12-01' from sysibm.sysdummy1
union all select date '2021-07-01', null from sysibm.sysdummy1
union all select null, date '2021-12-01' from sysibm.sysdummy1
union all select null, null from sysibm.sysdummy1
)
select mygreatest(x, y) as g from data;
Result:
G
----------
2021-12-01
2021-07-01
2021-12-01
null
See running example at db<>fiddle 2.

Fetching latest records of individual by joining 2 tables

I have to fetch the latest record of the student which derived by joining 2 tables:
table 1: table 2:
id name id marks EXAM attended time status
-------- ----------------------------------------------
1 ABC 1 90 2019-04-05 06:00:00 PASS
2 DEF 1 25 2018-06-05 08:00:00 FAIL
2 45 2019-03-05 06:00:00 FAIL
2 22 2019-01-05 09:00:00 FAIL
On joining both tables I got this:
# name marks EXAM ATTENDED TIME status
------------------------------------------------------
1 ABC 90 2019-04-05 06:00:00 PASS
2 ABC 25 2018-06-05 08:00:00 FAIL
3 DEF 45 2019-03-05 06:00:00 FAIL
4 DEF 22 2019-01-05 09:00:00 FAIL
5 DEF 55 2019-04-05 09:00:00 PASS
6 DEF 66 2019-05-05 09:00:00 PASS
7 DEF 99 2018-05-05 09:00:00 PASS
I want to fetch the latest result on datetime and name.
The output I need is:
id name marks EXAM ATTENDED TIME status
------------------------------------------------------
1 ABC 90 2019-04-05 06:00:00 PASS
6 DEF 66 2019-05-05 09:00:00 PASS
You can try below using correlated subquery
select * from table1 a1
inner join table2 a on a1.id=a.id
where exam_attended_time in (select max(exam_attended_time) from table2 b where a.id=b.id)
OR you can use row_number() if your db supports it-
select * from
(
select a.name,a1.*,row_number(partition by a.id order by exam_attended_time desc)rn from table1 a1
inner join table2 a on a1.id=a.id
)X where rn=1
You could use a window function (ROW_NUMBER).
SELECT
x.id
, x.NAME
, x.marks
, x.ExamAttendTime
, x.status
FROM
(
SELECT
t1.id
, t1.NAME
, t2.marks
, t2.ExamAttendTime
, t2.status
, ROW_NUMBER() OVER (PARTITION BY t1.id ORDER BY t2.ExamAttendTime DESC) AS ROWNUMBER
FROM
dbo.Table1 t1
JOIN dbo.Table2 t2 ON t2.id = t1.id
) x
WHERE
x.ROWNUMBER = 1
i don't know how you fetch the record like marks '99' and '66' and EXAM attended time
'2019-05-05 09:00:00 ' which is not available in table itself.
though this will might help you on getting correct data .
select a.id,a.name,b.marks,b.[EXAM attended time],b.[status] from table 1 a
join table 2 b on a.id=b.id where [EXAM attended time] in
(select max([EXAM attended time])[EXAM attended time]from exam group by id)
IF you are using SQL SERVER then you can use TOP as below to fetch latest records
SELECT A.id,
A.name,
B.marks,
B.EXAM_attended_time,
B.Status
FROM table1 A
OUTER APPLY (SELECT TOP 1 *
FROM table2 B WHERE B.id = A.id
ORDER BY B.EXAM_attended_time DESC) B
WHERE B.ID = A.id

How to join only latest date values from another table and prevent duplication

I'm trying to lookup a unique value from table b and get it into table a.
Table b stores multiple values that are changing by date.
I would like to join but only getting the values with the latest date from table b.
Table a
Unique ID
1
2
Table b
Date Unique ID Price
01/01/2019 1 100
01/02/2019 1 101
01/03/2019 1 102
01/01/2019 2 90
01/02/2019 2 91
01/03/2019 2 92
Expected result
Unique ID Price Date
1 102 01/03/2019
2 92 01/03/2019
Appreciate your help!
Have a sub-query that returns each UniqueID together with its max date. IN that result.
select * from tablename
where (UniqueID, date) in (select UniqueID, max(date)
from tablename
group by UniqueID)
You want correlated subquery :
select b.*
from tableb b
where b.date = (select max(b1.date) from tableb b1 where b1.UniqueID = b.UniqueID);
If you want to go with JOIN then you can do JOIN with subquery :
select a.UniqueID , b.Price, b.Date
from tablea a inner join
tableb b
on b.UniqueID = a.UniqueID
where b.date = (select max(b1.date) from tableb b1 where b1.UniqueID = a.UniqueID);
A correlated subquery?
select b.*
from b
where b.date = (select max(b2.date) from b b2 where b2.unique_id = b.unique_id);

MaxMin Function within Select Statement SQL 2012

I am having a few issues making a MAX function work within the select statement See example data below:
Table 1 Table 2
Visit_ID Car_ID Move_ID Visit_ID MoveStartDate MoveEndDate
A 1 1 A 25/07/2016 27/07/2016
B 2 2 A 28/07/2016 28/07/2016
C 1 3 B 19/07/2016 22/07/2016
D 3 4 D 28/06/2016 30/06/2016
I would like my select statement to pick the min start time and Max start time based on the Visit_ID so I would be expecting:
Result
Visit_ID Car_ID StartDate EndDate
A 1 25/07/2016 28/07/2016
B 2 19/07/2016 22/07/2016
So far I have tried I already have Inner Joins in my select statement:
,(MAX (EndDate) WHERE Visit.Visit_ID = Move.Visit_ID) AS End Date
I have looked at some other queries with a second select statement within the select so you end up with something like:
Select Visit_ID, Car_ID ,(Select MAX(EndDate) FULL OUTER JOIN Table 2 ON Table 1.Visit_ID = Table 2.Visit_ID Group By Table 1.Visit_ID) AS End Date
Hope I have provided enough info currently stumped.
If you also want Car_ID = 3 in the result:
select t1.Visit_ID, t1.Car_ID, MIN(MoveStartDate), MAX(MoveEndDate)
from table1 t1
join table2 t2 on t1.Visit_ID = t2.Visit_ID
group by t1.Visit_ID, t1.Car_ID
Returns:
SQL>select t1.Visit_ID, t1.Car_ID, MIN(MoveStartDate), MAX(MoveEndDate)
SQL&from table1 t1
SQL& join table2 t2 on t1.Visit_ID = t2.Visit_ID
SQL&group by t1.Visit_ID, t1.Car_ID;
visit_id car_id
======== =========== ==================== ====================
A 1 25/07/2016 28/07/2016
B 2 19/07/2016 22/07/2016
D 3 28/06/2016 30/06/2016
3 rows found
I did not check it but your can try this
WITH cte
AS
(select Move_ID,Visit_ID,min(MoveStartDate) AS mMS,MAX(MoveEndDate) AS mME
FROM Table_2
GROUP BY Move_ID,Visit_ID)
SELECT c.Move_ID,c.Visit_ID,T1.Car_ID,c.mMS,c.mME
FROM Table_1 as T1 JOIN cte as C
ON c.Visit_ID=T1.Visit_ID