Need only the most recent record
Current Data:
RequestID RequestCreateDate VehID DeviceNum ProgramStatus InvID
1 08/12/2018 13:00:00:212 110 20178 Submitted A1
2 08/11/2018 11:12:33:322 110 20178 Pending A1
3 09/08/2018 4:14:28:132 110 Null Cancelled A1
4 11/11/2019 10:12:00:123 188 21343 Open B3
5 12/02/2019 06:15:00:321 188 21343 Submitted B3
Req Result:
RequestID RequestCreateDate VehID DeviceNum ProgramStatus InvID
3 09/08/2018 4:14:28:132 110 Null Cancelled A1
5 12/02/2019 06:15:00:321 188 21343 Submitted B3
InvID is from tableB that I am joining.
Here is the query that I am currently trying but there are duplicate records:
Select
max(t1.RequestID) ReqID,
max(t1.RequestCreateDate) NewDate,
t1.VehID,
t1.DeviceNum,
t1.ProgramStatus,
t2.InvID
FROM table1 t1
LEFT JOIN table2 t2 ON t1.VehID = t2.VehID
GROUP BY t1.VehID, t1.DeviceNum, t1.ProgramStatus, t2.InvID
I need only the most recent record for each VehID. Thanks
On option is to filter with a subquery:
select t1.*, t2.invid
from table1
left join table2 t2 on t1.vehid = t1.vehid
where t1.requestCreateDate = (
select max(t11.requestCreateDate)
from table1 t11
where t11.vehid = t1.vehid
)
For performance, consider an index on table1(vehid, requestCreateDate).
You can also use row_number():
select *
from (
select t1.*, t2.invid, row_number() over(partition by vehid order by requestCreateDate desc) rn
from table1
left join table2 t2 on t1.vehid = t1.vehid
) t
where rn = 1
Related
T1 is a table of company and their (multiple users), T2 is table of registered users. I counted, for each company in T1, how many of their users are in T2 but need c3 to appear in the result table with #regUser == 0:
T1:
company user
c1 u1
c1 u2
c2 u2
c2 u3
c3 u4
c3 u1
T2:
user
u2
u3
So the resultant table should look like:
company #regUser
c1 1
c2 2
c3 0
With the following code I'm only getting the results for non-null companies:
select t1s.company, count(1)
from (select * from t1) t1s
cross apply (select *
from t2 t2s
where t2s.reguser = t1s.[user]) t12s
group by t1s.company
Thanks
just use left join
select t1.company,count(t2.user)
from t1 left join t2 on t1.user=t2.user
group by t1.company
the subquery is not necessary according to your requirement
but if you want to use apply then you need like below query
select t1s.company, count(t12s.Users)
from (select * from t1) t1s
outer apply (select Users
from t2 t2s
where t2s.Users = t1s.[Users]) t12s
group by t1s.company
output
company #regUser
c1 1
c2 2
c3 0
demolink
You can use a LEFT JOIN to get all the information of the left table with matching information from right table. By using a GROUP BY you can group the rows by company and get the COUNT of registered users for each company:
SELECT t1.company, COUNT(t2.[user]) AS regUser
FROM t1 LEFT JOIN t2 ON t1.[user] = t2.[user]
GROUP BY t1.company
ORDER BY t1.company ASC
You can also use the CROSS APPLY to solve this:
SELECT t1.company, SUM(CASE WHEN t1.[user] = t2.[user] THEN 1 ELSE 0 END) AS regUser
FROM t1 CROSS APPLY t2
GROUP BY t1.company
ORDER BY t1.company ASC
demo on dbfiddle.uk
All you need is a left join :
select company,count(t2.[user])
from t1 left outer join t2 on t1.[user]=t2.[user]
group by company
The question's query is overcomplicated. For example, from (select * from t1) t1s is equivalent to from t1 as t1s.
Just a LEFT JOIN with SUM()
CREATE TABLE T1(
Company VARCHAR(20),
Users VARCHAR(20)
);
CREATE TABLE T2(
Users VARCHAR(20)
);
INSERT INTO T1 VALUES
('c1', 'u1'),
('c1', 'u2'),
('c2', 'u2'),
('c2', 'u3'),
('c3', 'u4'),
('c3', 'u1');
INSERT INTO T2 VALUES
('u2'),
('u3');
SELECT T1.Company,
SUM(CASE WHEN T2.Users IS NULL THEN 0 ELSE 1 END) Cnt
FROM T1 LEFT JOIN T2
ON T1.Users = T2.Users
GROUP BY T1.Company;
Returns:
+---------+-----+
| Company | Cnt |
+---------+-----+
| c1 | 1 |
| c2 | 2 |
| c3 | 0 |
+---------+-----+
Live Demo
I have 2 tables (that's retrieving data from a main table). Example:
Table1
id GroupX Source GroupNum Amount
-------------------------------------------------------
1 23 School SH001 1 700
2 23 Bank BA001 2 300
3 23 Music MU001 3 500
4 23 School SH999 1 900
Table2
id GroupNum SourceAmt
----------------------------------
1 23 1 700
2 23 2 100
3 23 3 500
4 23 1 900
My dilemma is with the query I'm using. It's returning additional rows for split values(notice in table 2 "GroupNum" has a split value of 700 and 900)
My results should be
id GroupX Source GroupNum Amount SourceAmt
-----------------------------------------------------------------
1 23 School SH001 1 700 700
2 23 Bank BA001 2 300 100
3 23 Music MU001 3 500 500
4 23 School SH999 1 900 900
But instead I get this
id GroupX Source GroupNum Amount SourceAmt
-----------------------------------------------------------------
1 23 School SH001 1 700 700
2 23 School SH001 1 700 900
3 23 Bank BA001 2 300 100
4 23 Music MU001 3 500 500
5 23 School SH999 1 900 900
6 23 School SH999 1 900 700
Here's my query:
SELECT
t1.id,
t1.GroupX,
t1.Source,
t1.GroupNum,
t1.Amount,
t2.SourceAmt
FROM
table1 as t1
INNER JOIN
table2 as t2 ON t1.id = t2.id
AND t1.GroupNum = t2.GroupNum
WHERE
t1.id = 23
I've tried using Distinct as well. Assistance will be greatly appreciated.
If I understand correctly, you would like to join Table1 and Table2 such that the id, GroupNum, and amounts align. If this is indeed the case, then you'll need to join on the amounts as well, e.g.,:
Select t1.id, t1.Group, t1.Source, t1.GroupNum, t1.Amount, t2.SourceAmt
From table1 as t1 INNER JOIN
table2 as t2
ON t1.id = t2.id AND t1.GroupNum = t2.GroupNum AND t1.Amount = t2.SourceAmt
where id = 23
If this is not what you want, or you would prefer not to join using the amounts (e.g., you cannot guarantee that you won't see the same amount more than once), then you're in a bit of a conundrum; you'll note that (id, GroupNum) tuples are not unique in either table, and thus your join is not one-to-one. You may want to include Source in table2 or otherwise provide a transactionId in table1 that maps onto a unique ID column in table2.
You need an additional join key. There is no obvious candidate, except perhaps for amount -- but I'm not sure that is what you intend. SQL tables represent unordered sets, so there is no concept of matching by "line number".
You can assign a row number using row_number(). The following will do the match, but you need to specify the ordering column:
Select t1.id, t1.Group, t1.Source, t1.GroupNum, t1.Amount, t2.SourceAmt
From (select t1.*,
row_number() over (partition by t1.id order by ?) as seqnum
from table1 t1
) t1 inner join
(select t2.*
row_number() over (partition by t1.id order by ?) as seqnum
from table2 t2
) t2
on t1.id = t2.id and t1.GroupNum = t2.GroupNum and
t1.seqnum = t2.seqnum
where id = 23 ;
The ? is for the ordering column in each table.
I would choose a different approach from simple INNER JOIN, simply because you can do limited things with that result set (here's the result set from that inner join)
I would do multiple joins.
First I would LEFT JOIN with the default condition + where table1.[Amount] = table2.[SourceAmt]. This will give me set where [Amount] and [SourceAmt] are equal
After this I INNER JOIN with the default condition to get the Amounts that doesn't match
Here's the query
with t1 as
(
select 23 as [id], 'School' as [Group], 'SH001' as [Source], 1 as [GroupNum], 700 as [Amount]
union all
select 23, 'Bank', 'BA001', 2, 300
union all
select 23, 'Music', 'MU001', 3, 500
union all
select 23, 'School', 'SH999', 1, 900
),
t2 as
(
select 23 as [id], 1 as [GroupNum], 700 as [SourceAmt]
union all
select 23, 2, 100
union all
select 23, 3, 500
union all
select 23, 1, 900
)
select t1.*, a.*, b.*
from t1
left join t2 as a on
t1.[id] = a.[id]
and t1.[GroupNum] = a.[GroupNum]
and t1.[Amount] = a.[SourceAmt]
inner join t2 as b on
t1.[id] = b.[id]
and t1.[GroupNum] = b.[GroupNum]
where t1.[id] = 23
And here's the result set, which you can inspect
Now, I use this result as my pre-result actually, and do a little trick with CASE and [takeIt] column, here's the final query
with t1 as
(
select 23 as [id], 'School' as [Group], 'SH001' as [Source], 1 as [GroupNum], 700 as [Amount]
union all
select 23, 'Bank', 'BA001', 2, 300
union all
select 23, 'Music', 'MU001', 3, 500
union all
select 23, 'School', 'SH999', 1, 900
),
t2 as
(
select 23 as [id], 1 as [GroupNum], 700 as [SourceAmt]
union all
select 23, 2, 100
union all
select 23, 3, 500
union all
select 23, 1, 900
),
res as
(
select t1.[id],
t1.[Group],
t1.[Source],
t1.[GroupNum],
t1.[Amount],
isnull(a.[SourceAmt], b.[SourceAmt]) as [SourceAmt],
case when a.[SourceAmt] is null or a.[SourceAmt] = b.[SourceAmt] then 1
else 0
end as [takeIt]
from t1
left join t2 as a on
t1.[id] = a.[id]
and t1.[GroupNum] = a.[GroupNum]
and t1.[Amount] = a.[SourceAmt]
inner join t2 as b on
t1.[id] = b.[id]
and t1.[GroupNum] = b.[GroupNum]
where t1.[id] = 23
)
select [id],
[Group],
[Source],
[GroupNum],
[Amount],
[SourceAmt]
from res
where [takeIt] = 1
This may have been answered previously, but I'm having a difficult time describing my issue.
Let's say I have two tables
Table1
User, CalendarID
Joe 1
Joe 2
Joe 3
Sam 4
Bob 1
Jim 2
Jim 3
Table2
CalendarID, CalendarTime
1 2014-08-18 00:00:00.000
2 2015-01-19 00:00:00.000
3 2015-08-24 00:00:00.000
4 2016-01-18 00:00:00.000
What I would like to do is Join the two tables, only getting a single User Name, and Calendar ID based on what is this highest CalendarTime associated with that CalandarID.
So I would like the query to return
User CalendarID
Joe 3
Sam 4
Bob 1
Jim 3
The closest I've managed is
SELECT t1.User, MAX(t2.CalendarTIme) AS CalendarTime
FROM table1 t1
INNER JOIN table2 as t2
ON t1.CalendarID = t2.CalendarID
Group By t1.User
Which gets me the User and CalendarTime that I want, but not the Calendar ID, which is what I really want. Please help.
Closest to your script and pretty straightforward:
SELECT t1.User, t2.*
FROM table1 t1
INNER JOIN table2 as t2
ON t1.CalendarID = t2.CalendarID
WHERE NOT EXISTS
(
SELECT 1 FROM table1 t1_2
INNER JOIN table2 t2_2
ON t2_2.Calendar_ID = t1_2.Calendar_ID
WHERE t1_2.User = t1.User
AND t2_2.CalendarTime > t2.CalendarTime
)
This can be solved for the top N per group:
using top with ties with row_number():
select top 1 with ties
t1.User, t1.CalendarId, t2.CalendarTime
from table1 t1
inner join table2 as t2
on t1.Calendarid = t2.Calendarid
order by row_number() over (partition by t1.User order by t2.CalendarTime desc)
or using common table expression(or a derived table/subquery) with row_number()
;with cte as (
select t1.User, t1.CalendarId, t2.CalendarTime
, rn = row_number() over (partition by t1.User order by t2.CalendarTime desc)
from table1 t1
inner join table2 as t2
on t1.Calendarid = t2.Calendarid
)
select User, CalendarId, CalendarTime
from cte
where rn = 1
Table1
IssNo Qty
120 10
Table2
IssNo Qty
120 20
124 30
use this also :
From Table1-> substring(Table1.IssNo,1,2),at end I need to add "%" (eg) 12%
Now I need to check this like condition in table2 For Qty..And i need to add all Qty of 12% (eg) 20 and 30 will come..after SUM=> 50
My query is
Select Name,id,IssNo,address,Qty from Table1
(here Qty alone should be sum of Table2)
Expected o/p
IssNo Qty
120 50(Sum of Qty from Table2)
Try with this (assuming IssNo is a varchar):
Select t1.IssNo, Min(t1.Qty), Sum(t2.Qty)
from Table1 t1
Inner Join Table2 t2 On SUBSTRING(t2.IssNo, 1, 2) = SUBSTRING(t1.IssNo, 1, 2)
Group By t1.IssNo
This may help u...
Select t1.Name,t1.id,t1.IssNo,t1.address,sum(t2.Qty)
from Table1 t1
join (
select (IssNo/10) as IssNo,Qty Table2 t2
) t2 on t2.IssNo = (t1.IssNo)/10
group by t1.Name,t1.id,t1.IssNo,t1.address
This should be simple enough, but somehow my brain stopped working.
I have two related tables:
Table 1:
ID (PK), Value1
Table 2:
BatchID, Table1ID (FK to Table 1 ID), Value2
Example data:
Table 1:
ID Value1
1 A
2 B
Table 2:
BatchID Table1ID Value2
1 1 100
2 1 101
3 1 102
1 2 200
2 2 201
Now, for each record in Table 1, I'd like to do a matching record on Table 2, but only the most recent one (batch ID is sequential). Result for the above example would be:
Table1.ID Table1.Value1 Table2.Value2
1 A 102
2 B 201
The problem is simple, how to limit join result with Table2. There were similar questions on SO, but can't find anything like mine. Here's one on MySQL that looks similar:
LIMITing an SQL JOIN
I'm open to any approach, although speed is still the main priority since it will be a big dataset.
WITH Latest AS (
SELECT Table1ID
,MAX(BatchID) AS BatchID
FROM Table2
GROUP BY Table1ID
)
SELECT *
FROM Table1
INNER JOIN Latest
ON Latest.Table1ID = Table1.ID
INNER JOIN Table2
ON Table2.BatchID = Latest.BatchID
SELECT id, value1, value2
FROM (
SELECT t1.id, t2.value1, t2.value2, ROW_NUMBER() OVER (PARTITION BY t1.id ORDER BY t2.BatchID DESC) AS rn
FROM table1 t1
JOIN table2 t2
ON t2.table1id = t1.id
) q
WHERE rn = 1
Try
select t1.*,t2.Value2
from(
select Table1ID,max(Value2) as Value2
from [Table 2]
group by Table1ID) t2
join [Table 1] t1 on t2.Table1ID = t1.id
Either GROUP BY or WHERE clause that filters on the most recent:
SELECT * FROM Table1 a
INNER JOIN Table2 b ON (a.id = b.Table1ID)
WHERE NOT EXISTS(
SELECT 1 FROM Table2 c WHERE c.Table1ID = a.id AND c.BatchID > b. BatchID
)