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;
Related
I know this is simple for you sql people, but I am trying to combine two simple queries into one. It's probably obvious from the code that job.ActiveJob.ID = job.EstimateTbl.ID_Job.
I'm trying to get: id, JobName, sum(itemAmount)
Thanks for your help.
SELECT a.id, a.JobName
FROM job.ActiveJobsTbl AS a
WHERE a.ID = '100'
SELECT SUM(itemAmount)
FROM job.EstimateTbl
WHERE ID_Job = '100'
You can JOIN the tables by the ON E.ID_Job = A.ID and get the values in SELECT with GROUP BY
SELECT A.id, A.JobName, SUM(E.itemAmount) AS Amount
FROM job.ActiveJobsTbl AS A
INNER JOIN job.EstimateTbl E ON E.ID_Job = A.ID
WHERE A.ID = '100'
GROUP BY A.id, A.JobName;
using LEFT JOIN
SELECT a.id, a.JobName,EstimateTbl.itemAmount
FROM job.ActiveJobsTbl AS a
left join
(
SELECT SUM(itemAmount) itemAmount,ID_Job
FROM job.EstimateTbl
group by ID_Job
) EstimateTbl on EstimateTbl.ID_Job = a.ID
WHERE a.ID = '100'
You can use APPLY :
select a.id, a.JobName, t.itemAmount
from job.ActiveJobsTbl AS a OUTER APPLY
(SELECT SUM(t.itemAmount) AS itemAmount
FROM job.EstimateTbl AS t
WHERE t.ID_Job = a.ID
) t
WHERE a.ID = 100;
Try this:
SELECT A.id, A.JobName, SUM(E.itemAmount) AS Amount
FROM job.ActiveJobsTbl AS A
INNER JOIN job.EstimateTbl E ON E.ID_Job = A.ID
WHERE A.ID = '100'
GROUP BY A.id, A.JobName;
I have tables a, b, c, and d whereby:
There are 0 or more b rows for each a row
There are 0 or more c rows for each a row
There are 0 or more d rows for each a row
If I try a query like the following:
SELECT a.id, SUM(b.debit), SUM(c.credit), SUM(d.other)
FROM a
LEFT JOIN b on a.id = b.a_id
LEFT JOIN c on a.id = c.a_id
LEFT JOIN d on a.id = d.a_id
GROUP BY a.id
I notice that I have created a cartesian product and therefore my sums are incorrect (much too large).
I see that there are other SO questions and answers, however I'm still not grasping how I can accomplish what I want to do in a single query. Is it possible in SQL to write a query which aggregates all of the following data:
SELECT a.id, SUM(b.debit)
FROM a
LEFT JOIN b on a.id = b.a_id
GROUP BY a.id
SELECT a.id, SUM(c.credit)
FROM a
LEFT JOIN c on a.id = c.a_id
GROUP BY a.id
SELECT a.id, SUM(d.other)
FROM a
LEFT JOIN d on a.id = d.a_id
GROUP BY a.id
in a single query?
Your analysis is correct. Unrelated JOIN create cartesian products.
You have to do the sums separately and then do a final addition. This is doable in one query and you have several options for that:
Sub-requests in your SELECT: SELECT a.id, (SELECT SUM(b.debit) FROM b WHERE b.a_id = a.id) + ...
CROSS APPLY with a similar query as the first bullet then SELECT a.id, b_sum + c_sum + d_sum
UNION ALL as you suggested with an outer SUM and GROUP BY on top of that.
LEFT JOIN to similar subqueries as above.
And probably more... The performance of the various solutions might be slightly different depending on how many rows in A you want to select.
SELECT a.ID, debit, credit, other
FROM a
LEFT JOIN (SELECT a_id, SUM(b.debit) as debit
FROM b
GROUP BY a_id) b ON a.ID = b.a_id
LEFT JOIN (SELECT a_id, SUM(b.credit) as credit
FROM c
GROUP BY a_id) c ON a.ID = c.a_id
LEFT JOIN (SELECT a_id, SUM(b.other) as other
FROM d
GROUP BY a_id) d ON a.ID = d.a_id
Can also be done with correlated subqueries:
SELECT a.id
, (SELECT SUM(debit) FROM b WHERE a.id = b.a_id)
, (SELECT SUM(credit) FROM c WHERE a.id = c.a_id)
, (SELECT SUM(other) FROM d WHERE a.id = d.a_id)
FROM a
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
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
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