I have two tables and I need to get the sum of a.TOTAL * b.QUANTITY.
a (A_ID, TOTAL)
b (B_ID, QUANTITY)
So far I wrote:
SELECT a.A_ID, a.TOTAL * b.QUANTITY as calculation
FROM a INNER JOIN b ON
a.A_ID = b.B_ID
I tried ...SUM(a.TOTAL * b.QUANTITY) as calculation but it doesn't work. I would be grateful for any help!
Try this :
SELECT A_ID, SUM(calculation) as mySum
FROM (
SELECT a.A_ID, a.TOTAL * b.QUANTITY as calculation
FROM a INNER JOIN b ON
a.A_ID = b.B_ID
) q
GROUP BY A_ID
Did you intend to do a grouping on A's id. If so, then this might give your desired result:
SELECT a.A_ID,
SUM(a.TOTAL * b.QUANTITY) AS calculation
FROM a
INNER JOIN b
ON a.A_ID = b.B_ID
GROUP BY a.A_ID
Related
I have 3 tables A,B and C as shown below.
All the 3 tables have a common CUST_ID column. And table A and B have 2 common columns CUST_ID and A_ID. I have to display the NAME from table C, Count of Test_ID from table B for each CUST_ID and START and END from table A. The expected result table is like,
I tried inner join like,
select C.Name ,A.Start,A.[End]
from
C
inner join
B
on C.CUST_ID = B.CUST_ID
inner join
A
on A.A_ID = B.A_ID and A.CUST_ID = B.CUST_ID
but its giving total 7 rows. How to display the count of Test_ID for east CUST_ID and display it in only 4 rows as shown in the expected result table?
Try this
SELECT C.NAME, Tmp.Test_COUNT, A.START, A.END
FROM C INNER JOIN A ON C.CUST_ID = A.CUST_ID
INNER JOIN
(
SELECT CUST_ID, A_ID, COUNT(*) AS Test_COUNT
FROM B
GROUP BY CUST_ID, A_ID
) Tmp ON Tmp.CUST_ID = A.CUST_ID AND Tmp.A_ID = A.A_ID
You need to use a subquery to obtain the test counts in table B, and join this table instead of joining B directly:
SELECT C.NAME, t.Test_COUNT, A.START, A.END
FROM C
INNER JOIN A
ON C.CUST_ID = A.CUST_ID
INNER JOIN
(
SELECT A_ID, COUNT(*) AS Test_COUNT
FROM B
GROUP BY A_ID
) t
ON t.A_ID = A.A_ID
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
I have multiple related tables in a database and each can be updated separately and have their own LastUpdated Date field. In one of these tables there is more than one LastUpdated field each indicating from which source that record was updated. We commonly query these multiple tables as a single item with joins and thus I would like to know for each record what the most recent LastUpdated record is across all joins. I know this can be achieved with many sub-queries but I was wondering whether there was something along the lines of the Coalesce function into which you can pass many fields and it returns the first non-null value.
So it would read something like:
SELECT a.a_id,
a.name,
b.b_id,
b.detail,
c.c_id,
c.otherfield,
Maxdate(a.lastupdated, a.lastupdatedfromweb, b.lastupdated,
c.lastupdated) AS
LastUpdatedDate
FROM a
INNER JOIN b
ON a.a_id = b.a_id
INNER JOIN c
ON b.b_id = c.b_id
Any ideas? Could this be written as a custom function or does it exist in the box? I am working on SQL Server 2005 and 2008 if that helps.
In 2008+ you can use CROSS APPLY to create a row for each of your dates, then select the Max:
SELECT
a.a_Id,
a.Name,
b.b_Id,
b.Detail,
c.c_Id,
c.OtherField,
ld.LastUpdatedDate
FROM
a INNER JOIN b ON a.a_Id = b.a_Id
INNER JOIN c ON b.b_Id = c.b_Id
CROSS APPLY
( SELECT LastUpdatedDate = MAX(LastUpdatedDate)
FROM (VALUES
(a.LastUpdated),
(a.LastUpdatedFromWeb),
(b.LastUpdated),
(c.LastUpdated)
) d (LastUpdatedDate)
) ld
You could also do this as a correlated subquery, but during optimisation SQL Server will rewrite correlated subqueries as OUTER APPLY so I prefer to just cut a step out and write the APPLY myself, as I have found some unusual behaviour when SQL deconstructs the correlated subquery and rewrites it as an APPLY. More details of this are described in this answer
For 2005, I think you will need to use a slightly different method as it doesn't support table valued constructors:
SELECT
a.a_Id,
a.Name,
b.b_Id,
b.Detail,
c.c_Id,
c.OtherField,
ld.LastUpdatedDate,
( SELECT MAX(CASE Number
WHEN 1 THEN a.LastUpdated
WHEN 2 THEN a.LastUpdatedFromWeb
WHEN 3 THEN b.LastUpdated
WHEN 4 THEN c.LastUpdated
END)
FROM (SELECT TOP 4 Number = ROW_NUMBER() OVER(ORDER BY object_id)
FROM sys.all_objects) n
) AS LastUpdated
FROM
a INNER JOIN b ON a.a_Id = b.a_Id
INNER JOIN c ON b.b_Id = c.b_Id;
Or:
SELECT
a.a_Id,
a.Name,
b.b_Id,
b.Detail,
c.c_Id,
c.OtherField,
ld.LastUpdatedDate,
( SELECT MAX(LastUpdated)
FROM ( SELECT a.LastUpdated UNION ALL
SELECT a.LastUpdatedFromWeb UNION ALL
SELECT b.LastUpdated UNION ALL
SELECT c.LastUpdated
) d
) AS LastUpdated
FROM
a INNER JOIN b ON a.a_Id = b.a_Id
INNER JOIN c ON b.b_Id = c.b_Id;
Unfortunately I no longer have any 2005 instances installed so I can't test this.
EDIT
Just realised that you wanted the source of the field too, and also remembered that 2005 does support the use of APPLY, so for 2008+:
SELECT
a.a_Id,
a.Name,
b.b_Id,
b.Detail,
c.c_Id,
c.OtherField,
ld.LastUpdatedDate,
ld.FieldName
FROM
a INNER JOIN b ON a.a_Id = b.a_Id
INNER JOIN c ON b.b_Id = c.b_Id
CROSS APPLY
( SELECT TOP 1 LastUpdatedDate, FieldName
FROM (VALUES
(a.LastUpdated, 'a.LastUpdated'),
(a.LastUpdatedFromWeb, 'a.LastUpdatedFromWeb'),
(b.LastUpdated, 'b.LastUpdated'),
(c.LastUpdated, 'c.LastUpdated')
) d (LastUpdatedDate, FieldName)
ORDER BY LastUpdated DESC
) ld
For 2005:
SELECT
a.a_Id,
a.Name,
b.b_Id,
b.Detail,
c.c_Id,
c.OtherField,
ld.LastUpdatedDate,
ld.FieldName
FROM
a INNER JOIN b ON a.a_Id = b.a_Id
INNER JOIN c ON b.b_Id = c.b_Id
CROSS APPLY
( SELECT TOP 1 LastUpdatedDate = LastUpdated, FieldName
FROM (
SELECT a.LastUpdated, FieldName = 'a.LastUpdated' UNION ALL
SELECT a.LastUpdatedFromWeb, 'a.LastUpdatedFromWeb' UNION ALL
SELECT b.LastUpdated, 'b.LastUpdated' UNION ALL
SELECT c.LastUpdated, 'c.LastUpdated'
) d
ORDER BY LastUpdated DESC
) ld
SELECT
a.a_Id,
a.Name,
b.b_Id,
b.Detail,
c.c_Id,
c.OtherField,
MAX(SELECT a.LastUpdated, a.LastUpdatedFromWeb, b.LastUpdated, c.LastUpdated FROM a INNER JOIN b ON a.a_Id = b.a_Id INNER JOIN c ON b.b_Id = c.b_Id) AS LastUpdatedDate
FROM
a INNER JOIN b ON a.a_Id = b.a_Id
INNER JOIN c ON b.b_Id = c.b_Id
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;
I am trying to get row count from the following query. I get only row count as 1 but there are 35 records. Could you please let me know how to get the count from inner query?
Thank you
SELECT COUNT(*)(SELECT DISTINCT a.my_id, a.last_name, a.first_name, b.temp_val
FROM Table_A a INNER JOIN Table_B b on a.a_id = b.a_id)
You're missing a FROM and you need to give the subquery an alias.
SELECT COUNT(*) FROM
(
SELECT DISTINCT a.my_id, a.last_name, a.first_name, b.temp_val
FROM dbo.Table_A AS a
INNER JOIN dbo.Table_B AS b
ON a.a_id = b.a_id
) AS subquery;