SQL Select MAX w/ Left Join - sql

SELECT a.first, a.last, b.number, c.last_login
FROM Table1 a
LEFT JOIN Table2 b ON a.first = b.first AND a.last = b.last
LEFT JOIN Table3 c ON b.number = c.number
Sometimes their are multiple entries for the number and I need to only select the max number from table b, however, when i try
SELECT a.first, a.last, MAX(b.number), c.last_login
I get an error. What can I do to select the maximum b.number?

EDIT : Many years I haven't done SQLServer, but maybe the Analytic function can do the trick
SELECT v.first, v.last, c.number, c.last_login
FROM (
SELECT a.first, a.last, LAST_VALUE(b.number) OVER (PARTITION BY a.first, a.last ORDER BY a.first, a.last, b.number) AS yourmax
FROM Table1 a
LEFT JOIN Table2 b ON a.first = b.first AND a.last = b.last
GROUP BY a.first, a.last
) v
INNER JOIN Table3 c ON v.yourmax = c.number
Can you confirm this? I haven't sqlserver, but on oracle the MAX() OVER (...) exists.
LAST_VALUE isn't the only keyword applying to OVER analitics

If you want the max number you can use
SELECT a.first, a.last, b.MaxNumber, c.last_login
FROM Table1 a
LEFT JOIN (select tmp.first, tmp.last, max(tmp.number) MaxNumber from Table2 tmp
group by tmp.first, tmp.last
) b
ON a.first = b.first AND a.last = b.last
LEFT JOIN Table3 c ON b.MaxNumber = c.number

Related

Is it possible to do a nested left join within another left join?

So I want to do something like this:
SELECT ACC_NO
FROM
TABLENAME A
LEFT JOIN
(
TABLENAME B
LEFT JOIN TABLENAME C
ON B.FIELDNAME = C.FIELDNAME
) D
ON A.FIELDNAME = D.FIELDNAME
How would I achieve this?
Yes it is possible, Try like below
SELECT A.ACC_NO,A.FIELDNAME
FROM
TABLENAME A
LEFT JOIN
(
select B.* from TABLENAME B
LEFT JOIN TABLENAME C
ON B.FIELDNAME = C.FIELDNAME
) D
ON A.FIELDNAME = D.FIELDNAME
Yes, you can:
SELECT ACC_NO
FROM TABLENAME A LEFT JOIN
(TABLENAME B LEFT JOIN
TABLENAME C
ON B.FIELDNAME = C.FIELDNAME
) -- No alias is necessary
ON A.FIELDNAME = B.FIELDNAME;
However, this is unnecessary and verbose. Instead:
SELECT ACC_NO
FROM TABLENAME A LEFT JOIN
TABLENAME B
A.FIELDNAME = B.FIELDNAME LEFT JOIN
TABLENAME C
ON B.FIELDNAME = C.FIELDNAME;
I assume your query is actually more complex. This version is presumably equivalent to:
SELECT A.ACC_NO
FROM TABLENAME A
Unless you are interested in actually seeing duplicates that might be generated by the JOINs.

SQL query inner join and where on the second table

I have a oracle database and I'm trying to query data in table1 and inner join with another table2 where one of the columns(date) is equal to the most recent date and another column in table2(built) is equal to 'yes'. This query below is not picking up the where function and can't pinpoint why
SELECT id, b, c, d
FROM table1 a
INNER JOIN table2 b on b.id = a.id
WHERE b.date =(SELECT MAX(date) FROM table2) AND b.built = 'yes'
Actual query
SELECT m_tp_str, m_tp_trn, m_tp_dte, m_tp_buy, m_tp_qtyeq, m_tp_nom, m_instr,
m_tp_p, m_tp_status2
FROM HA_PRD_DM.TP_ALL_REP a INNER JOIN HA_PRD_DM.UDF_CURR_REP b
ON a.m_udf_ref2 = b.m_nb
WHERE b.m_rep_date2 = (SELECT MAX(c.m_rep_date2) FROM HA_PRD_DM.UDF_CURR_REP c)
AND b.m_purpose = 'yes'
You can do this using analytic functions:
SELECT id, b, c, d
FROM table1 a INNER JOIN
(SELECT b.*, MAX(date) OVER (PARTITION BY b.id) as max_date
FROM table2 b
WHERE built = 'yes'
) b
ON b.id = a.id AND b.max_date = b.date;

Sql select statement while getting total of one value

Hi I have following select statement
select
a.amount
,b.des
,a.id
,SUM(a.amount) as total
,b.id
from t_sales a
left outer join t_location b on(b.id=a.orgId)
where a.Id=#salesId and
a.sId=#supId
GROUP BY a.amount, b.des, a.Id,b.id;
Everything is working fine, except total. I am trying to get total of a.amount which is returning 15 values so I want to have total of all 15 values. Please let me know how to fix it.
Thanks
You should remove a.amount column from select list ( aggregate column should not exists in select list)
select b.des, a.id, a.amount ,SUM(a.amount) over(partition by 1) as total, b.id from t_sales a left outer join t_location b on(b.id=a.orgId)
where a.Id=#salesId and a.sId=#supId GROUP BY b.des, a.Id, b.id;
Please try:
select
a.amount
,b.des
,a.id
,SUM(a.amount) over(partition by 1) as total
,b.id
from t_sales a
left outer join t_location b on(b.id=a.orgId)
where
a.Id=#salesId and
a.sId=#supId;
Can you try
select a.amount, b.des, a.id, b.id,
(select sum(a.amount)
from t_sales a
left outer join t_location b on (b.id = a.orgId)
where a.Id = #salesId
and a.sId = #supId
GROUP BY b.des, a.Id, b.id) as total
from t_sales a
left outer join t_location b on (b.id = a.orgId)
where a.Id = #salesId
and a.sId = #supId
GROUP BY a.amount, b.des, a.Id, b.id;

Combining 3 separate sql queries into one result

So I have three sql queries requesting 3 different things
but I want to be able to combine them into 1 table so that each query appears in each column
these are the queries:
select b.name, count(*)
from account a join branch b
on a.open_branch_id = b.branch_id
group by b.name;
select b.name, count(*)
from employee e join branch b
on e.assigned_branch_id = b.branch_id
group by b.name;
select b.name, count(*)
from customer c join branch b
on c.city = b.city
group by b.name;
i don't know how to combine them so query 1 will appear in 1 column, query 2 in the 2nd column, and query 3 in the third column.
Anyone have any ideas?
Thanks
If the name column is going to have the same values, you can join them like this. From your query however, it seems that the names you are showing are of branches, employees and customers.
select b.name as Name, count(*) as [Count] into #Result1 from account a join branch b on a.open_branch_id = b.branch_id group by b.name;
select b.name as Name, count(*) as [Count] into #Result2 from employee e join branch b on e.assigned_branch_id = b.branch_id group by b.name;
select b.name as Name, count(*) as [Count] into #Result3 from customer c join branch b on c.city = b.city group by b.name;
select r1.name,
r1.[Count],
r2.[Count],
r3.[Count],
from #Result1 as r1
left join #Result2 as r2 on r1.name = r2.name
left join #Result3 as r3 on r1.name = r3.name
drop table #Result1
drop table #Result2
drop table #Result3
If I'm understanding your question, you want to join your results based on your name field from each query? Assuming each have the same names, you can do this with JOINs and subqueries. Here is a simplified version (replace the subqueries with yours above):
select t1.name, t1.cnt,
t2.name as t2name, t2.cnt as t2cnt,
t3.name as t3name, t3.cnt as t3cnt
from
(select name, count(1) cnt
from t1
group by name) t1 join
(select name, count(1) cnt
from t2
group by name) t2 on t1.name = t2.name join
(select name, count(1) cnt
from t3
group by name) t3 on t1.name = t3.name
SQL Fiddle Demo
Edit, given your comments, it appears this is what you might be looking for:
select b.name,
a.acctcnt, e.empcnt, c.citycnt
from branch b
left join (
select count(1) acctcnt, open_branch_id
from account
group by open_branch_id
) a on a.open_branch_id = b.branch_id
left join (
select count(1) empcnt, assigned_branch_id
from employee
group by assigned_branch_id
) e on e.assigned_branch_id = b.branch_id
left join (
select count(1) citycnt, city
from customer
group by city
) c on c.city = b.city
More Fiddle
You could do it like this (SQL Server 2005 and up):
SELECT
B.Name,
B.OtherColumnsIfYouLike,
ACount = IsNull(ACount, 0),
ECount = IsNull(E.ECount, 0),
CCount = IsNull(C.CCount, 0)
FROM
dbo.Branch B
OUTER APPLY (
SELECT ACount = Count(*)
FROM dbo.Account A
WHERE B.Branch_ID = A.Open_Branch_ID
) A
OUTER APPLY (
SELECT ECount = Count(*)
FROM dbo.Employee E
WHERE B.Branch_ID = E.Assigned_Branch_ID
) E
OUTER APPLY (
SELECT CCount = Count(*)
FROM dbo.Customer C
WHERE B.City = C.City
) C
;
Any query you use needs to pay attention to whether there may be no results at all for that branch name. Using INNER JOIN (or just JOIN) will exclude these instead of properly showing 0.
Using your existing queries intact will work like the following, but won't perform as well:
SELECT
Name = Coalesce(A.Name, E.Name, C.Name),
ACount = IsNull(ACount, 0),
ECount = IsNull(E.ECount, 0),
CCount = IsNull(C.CCount, 0)
FROM
(
select b.name, ACount = Count(*)
from account a join branch b on a.open_branch_id = b.branch_id
group by b.name
) A
FULL JOIN (
select b.name, ECount = Count(*)
from employee e join branch b on e.assigned_branch_id = b.branch_id
group by b.name
) E ON A.Name = E.Name
FULL JOIN (
select b.name, CCount = Count(*)
from customer c join branch b on c.city = b.city group by b.name
) C ON IsNull(A.Name, E.Name) = C.Name
;
I think this is the fastest:
with a as
(
select open_branch_id as b_id, count(*) as a_count
from account a
group by open_branch_id
), e as
(
select assigned_branch_id as b_id, count(*) as e_count
from employee e
group by assigned_branch_id
), c as
(
select b.branch_id as b_id, count(*) as c_count
from customer c join branch b
on c.city = b.city
group by b.name
)
select b.name, a.a_count, e.e_count, c.c_count
from branch b
left join a on a.b_id = b.branch_id
left join e on e.b_id = b.branch_id
left join c on c.b_id = b.branch_id
order by b.name

Getting MIN date

I have a table(A) that looks something like:
ID Date
1 2012/01/12
2 2012/01/01
3 2012/01/03
4 2012/03/12
If I wanted to grab the MIN date for this query, would I just group by?
select
a.ID,
MIN(a.DATE),
b.name,
c.price
FROM
tablea a inner join tableb b on a.ID = b.ID
inner join tablec c b.ID = c.ID
You want a window function. The correct expression is:
select a.id,
min(a.date) over () as mindate,
b.name, c.price
. . .
This says to get the min of the date over the data. There is no partition, so it gets it over all the data.
If you are looking for those that had the minimum date, then you can do this:
select
a.ID,
a.DATE,
b.name,
c.price
FROM tablea a
INNER JOIN
(
SELECT Id, MIN(Date) AS MinDate
FROM tablea
GROUP BY Id
) As minA ON a.date = mina.mindate AND a.id = mina.id
inner join tableb b on a.ID = b.ID
inner join tablec c b.ID = c.ID
WITH recordList
as
(
select a.ID,
a.DATE,
b.name,
c.price,
DENSE_RANK() OVER (PARTITION BY a.ID
ORDER BY a.Date ASC) rn
FROM tablea a
inner join tableb b on a.ID = b.ID
inner join tablec c b.ID = c.ID
)
SELECT ID, DATE, name, Price
FROM recordList
WHERE rn = 1