Sum query with reference to different coloumn for each row? - sql

Is it possible to carry out a sum query where the row for each part of the sum is determine from a join?
For example if I have tables
table A
id | value
1 | 10
2 | 15
3 | 10
And
table b
id | b | c
1 | 2 | 3
2 | 1 | 2
Is it possible to do a SUM(tableA.value * tableB.<specific_column>) Where either the SUM is carried out directly as a join or the join table is prequired from a specification, for sake of argument, a string "bcb"?
Edit:
The end result I'm hoping to achieve would be equivalent to this:
SUM(SELECT value * b FROM tableA a JOIN tableB b ON b.id = 1 WHERE a.id = 1,
SELECT value * c FROM tableA a JOIN tableB b ON b.id = 1 WHERE a.id = 2,
SELECT value * b FROM tableA a JOIN tableB b ON b.id = 2 WHERE a.id = 3);
I guess there's two parts to this: A simple join of A and selected values from B such that B is reduced to a single selectValue column.
Thanks.

As asked in comment it should be better to show us what output you really wants, but as I understand you wants to do something like :
SELECT id, SUM(a.value * b.b)
FROM a JOIN b USING(id)
GROUP BY id;
It's what you want ? I do not really understand you "bcb" point ...
Not because in your comment you said SUM(value, value, value) and I think you want to add those values so, I'll do something like this :
WITH
sum1 AS (SELECT value * b AS res
FROM tableA a
JOIN tableB b ON b.id = 1
WHERE a.id = 1),
sum2 AS (SELECT value * c AS res
FROM tableA a
JOIN tableB b ON b.id = 1
WHERE a.id = 2),
sum3 AS (SELECT value * b AS res
FROM tableA a
JOIN tableB b ON b.id = 2
WHERE a.id = 3)
SELECT SUM(sum1.res + sum2.res + sum3.res)
FROM sum1, sum2, sum3;

I've tested #Hervé Piedvache's code and it returns NULL, because SELECT value * b AS val FROM tableA a JOIN tableB b ON b.id = 1 WHERE a.id = 1 has two rows. A work around would be:
SELECT SUM(val) FROM
(SELECT value * b AS val FROM tableA a JOIN tableB b ON b.id = 1 WHERE a.id = 1
UNION
SELECT value * c AS val FROM tableA a JOIN tableB b ON b.id = 1 WHERE a.id = 2
UNION
SELECT value * b AS val FROM tableA a JOIN tableB b ON b.id = 2 WHERE a.id = 3) data;

Related

How to find rows missing by every group

I have two tables:
Input:
A:
ID col
1 a
1 b
1 c
2 a
2 b
3 x
4 y
B
ID col
1 a
1 b
2 a
I want to for every ID in B, find rows in A but not in B by every ID.
Output:
ID Col
1 c
2 b
What I tried:
left/right join. I am trying something like select * from a left join b on a.id = b.id where b.id is null
except. select * from a except select * from b
but not sure how to modify it.
Assuming you want the values in A for which there are records in B with the same ID, but not the same col, you could do:
select
a.ID,
a.col
from A
left join B
on b.ID = a.ID and b.col = a.col
where A.ID in (select distinct ID from B) -- B contains this `ID` somewhere...
and B.ID is null -- ...but not with the same `col`
Test it here.
Using a combination of exists and not exists.
select *
from a
where exists (select 1 from b where a.id=b.id) --id check
and not exists (select 1 from b where a.id=b.id and a.col=b.col) -- col check

Left join tables, add to on expression

I have a problem with left join two tables. Please help me.
I have two tables:
So if TableA is
A B
1 a
2 b
3 c
and TableB is
A B
1 d
2 e
Then Select * from TableA left join TableB on TableA.A = TableB.A returns
1 a 1 d
2 b 2 e
3 c null null
But: Select * from TableA left join TableB on TableA.A = TableB.A where TableB.B = 'e' returns:
2 b 2 e
And question, How I can get some like this:
2 b 2 e
3 c null null
Thank you very much.
It seems you want to get all matches from TableB, where B field is either equal to 'e' or NULL:
Select *
from TableA
left join TableB on TableA.A = TableB.A
where (TableB.B = 'e') or (TableB.B is null)
Here you go
Select * from TableA left join TableB on TableA.A = TableB.A
where TableB.B = 'e' OR TableB.B is NULL
And you will get null rows from tableB in addition of rows that match with Table.B='e'

SQL Server, selecting from 2 columns from different tables

I have these columns from 2 tables
Table1 Table2
Code ID Code ID
A 1 A 1
B 1 B 1
C 1 C 1
D 1
E 1
My query:
Select
a.id, a.code, b.code
from
Table1 a, Table2 b
where
a.id = '1' and a.id = b.id
What I expected
ID code code
1 A A
1 B B
1 C C
1 D NULL
1 E NULL
What I got
ID code code
1 A A
1 B A
1 C A
1 D A
1 E A
1 A B
1 B B
1 C B
....
Any ideas? distinct didn't help
Thanks
Well, all the ID's in both tables are 1, so by joining on ID you'll get the cartesian product of both tables.
Instead, you'll need to do a left outer join based on Table1.Code:
Select a.id, a.code, b.code
from Table1 a LEFT OUTER JOIN Table2 b
on a.code = b.code
where a.id = '1';
You need to do a LEFT OUTER JOIN instead of a Cartesian Product
SELECT a.Id, a.Code, b.Code FROM Table1 a
LEFT OUTER JOIN Table2 b ON a.Code = b.Code
WHERE a.Id = '1'
A LEFT OUTER JOIN returns all rows from the left-hand side of the join (in this case Table 1) regardless of whether there is a matching record in the table on the right-hand side of the join (in this case Table 2). Where there is no match a NULL is returned for b.Code as per your requirements.
Reference OUTER JOINS

SQL aggregation query, grouping by entries in junction table

I have TableA in a many-to-many relationship with TableC via TableB. That is,
TableA TableB TableC
id | val fkeyA | fkeyC id | data
I wish the do select sum(val) on TableA, grouping by the relationship(s) to TableC. Every entry in TableA has at least one relationship with TableC. For example,
TableA
1 | 25
2 | 30
3 | 50
TableB
1 | 1
1 | 2
2 | 1
2 | 2
2 | 3
3 | 1
3 | 2
should output
75
30
since rows 1 and 3 in Table have the same relationships to TableC, but row 2 in TableA has a different relationship to TableC.
How can I write a SQL query for this?
SELECT
sum(tableA.val) as sumVal,
tableC.data
FROM
tableA
inner join tableB ON tableA.id = tableB.fkeyA
INNER JOIN tableC ON tableB.fkeyC = tableC.id
GROUP by tableC.data
edit
Ah ha - I now see what you're getting at. Let me try again:
SELECT
sum(val) as sumVal,
tableCGroup
FROM
(
SELECT
tableA.val,
(
SELECT cast(tableB.fkeyC as varchar) + ','
FROM tableB WHERE tableB.fKeyA = tableA.id
ORDER BY tableB.fkeyC
FOR XML PATH('')
) as tableCGroup
FROM
tableA
) tmp
GROUP BY
tableCGroup
Hm, in MySQL it could be written like this:
SELECT
SUM(val) AS sumVal
FROM
( SELECT
fkeyA
, GROUP_CONCAT(fkeyC ORDER BY fkeyC) AS grpC
FROM
TableB
GROUP BY
fkeyA
) AS g
JOIN
TableA a
ON a.id = g.fkeyA
GROUP BY
grpC
SELECT sum(a.val)
FROM tablea a
INNER JOIN tableb b ON (b.fKeyA = a.id)
GROUP BY b.fKeyC
It seems that is it needed to create a key_list in orther to allow group by:
75 -> key list = "1 2"
30 -> key list = "1 2 3"
Because GROUP_CONCAT don't exists in T-SQL:
WITH CTE ( Id, key_list )
AS ( SELECT TableA.id, CAST( '' AS VARCHAR(8000) )
FROM TableA
GROUP BY TableA.id
UNION ALL
SELECT TableA.id, CAST( key_list + ' ' + str(TableB.id) AS VARCHAR(8000) )
FROM CTE c
INNER JOIN TableA A
ON c.Id = A.id
INNER join TableB B
ON B.Id = A.id
WHERE A.id > c.id --avoid infinite loop
)
Select
sum( val )
from
TableA inner join
CTE on (tableA.id = CTE.id)
group by
CTE.key_list

How can I get the exact match join for the below scenario?

How can i join the below tables
TableA TableB TableC TableD
ID ID_C ID ID_A Value ID ID ID_C Value
1 1 1 1 a 1 1 1 a
2 1 b 2 1 b
in order to get the Result like
Result
ID ID_B Value ID_C ID_D Value
1 1 a 1 1 a
1 2 b 1 2 b
and my result shouldn't contain 1 2 b 1 1 b and both value columns cannot always have same values so it cannot be used in a condition.
To make it simplier,
Resultant Table TableA TableB
ID Value ID Value ID ID_A
1 a 1 a 1 1
1 b 2 g 2 1
2 a 3 d 3 2
3 c 4 3
Now i need to join the Resultant Table with TableA,TableB inorder to get some of the columns from TableA,TableB and ResultantTable.ID=TableA.ID and TableB.ID_A=TableA.ID since its a foreign key.
Doing the Join with TableB turns to duplicates. Since ID=1 occurs twice i get 4 records where ID=1, when there are only 2 records. It can be done with distinct or group by but i need other columns as well to be displayed.How do i do both in the process.
SELECT A.ID, B.ID, B.Value, C.ID, D.ID, D.Value
FROM TableA A
INNER JOIN TableB B ON A.ID = B.ID_A
INNER JOIN TableC C ON A.ID_C = C.ID
INNER JOIN TableD D ON B.ID = D.ID AND C.ID = D.ID_C
You tell us that the field "value" in TableB should not be different from the field "value" in TableD? Could we replace the B.ID = D.ID with B.Value = D.Value so solve your problem?
Are you sure, that is the way that is suppose to work?
Try:
SELECT A.ID, B.ID ID_B, B.Value Value_B, C.ID ID_C, D.ID ID_D, D.Value Value_D
FROM TableA A
JOIN TableB B ON A.ID = B.ID_A
JOIN TableC C ON A.ID_C = C.ID
JOIN TableD D ON B.Value = D.Value AND C.ID = D.ID_C