Conditional sum in SQL (SAS) (SUMIFS equivalent) - sql

Let say I am working under SAS EG and I have 2 tables:
Table1:
Id Item
1 A
1 B
1 C
2 B
2 D
3 C
3 E
3 F
Table2:
Id Item Amount
1 A 99
2 C 100
1 B 100
2 A 90
1 A 93
3 B 92
1 E 93
2 B 99
1 A 93
Now I would like to take the sum conditional for my table1 from table2 (when the ID and the Item match).
Id Item Want
1 A 285
1 B 100
1 C 0
2 B 99
2 D 0
3 C 0
3 E 0
3 F 0
So what am I supposed to do in SQL?
Thanks in advance.

Use a correlated subquery to SUM:
select t1.Id, t1.Item,
(select sum(t2.amount) from table2 t2 where t2.id = t1.id and t2.item = t1.item)
from table1 t1

This looks like aggregation to me, with a left join:
select t1.id, t1.item,
coalesce(sum(t2.amount), 0) as want
from table1 t1 left join
table2 t2
on t1.id = t2.id and t2.item = t2.item
group by t1.id, t1.item;

Related

how to join with complecated condition in redshift

I have following table1
id name
1 A
3 B
and table2
id label value
1 a 10
1 b 11
1 c 12
2 a 13
2 b 14
2 c 15
3 a 16
3 b 17
3 c 18
My desired result is following.I'd like to join table1 and table2 in label=a and b
I guess I must join twice in each condition..
id name a b
1 A 10 11
3 B 16 17
I tried following one, but I get only result in label = a
select *
from table1
left join table2 using(id)
where label in ('a')
Are there any good way to achieve this?
I guess we need transpose
Thanks
Redshift doesn't have a native pivot function so you need to do it using a case statement:
SELECT
table1.id,
table1.name,
SUM(CASE WHEN table2.label = 'a' THEN table2.value END) AS a,
SUM(CASE WHEN table2.label = 'b' THEN table2.value END) AS b
FROM table1
LEFT JOIN table2
ON table1.id = table2.id
GROUP BY table1.id, table1.name
See this link also:
Pivot for redshift database

If value in both table then assign 1

Table1 CompanyID Location #-of-employees
5234 NY 10
5268 DC 2
5879 NY 8
6897 KS 100
8789 CA 1
9992 OH 201
9877 TX 15
Table2 CompanyID #-of-Shareholders
5234 5
5879 2
6897 4
8789 2
I have two table with the column CompanyID. In table2 you can find companies that have shareholders and in table1 you can find all the companies. So in table 1 I want to add a dummy variable that assign a 1 if the companyID is in table2(which means the company has shareholders) and a 0 if not.
Expected output:
Table1 CompanyID Location #-of-employees Dummy
5234 NY 10 1
5268 DC 2 0
5879 NY 8 1
6897 KS 100 1
8789 CA 1 1
9992 OH 201 0
9877 TX 15 0
I tried using this query but it doesn't give me the output I expect.
SELECT CASE WHEN companyID IN table2 THEN 1
ELSE 0
END AS dummy
FROM table1
You have to use the Subquery for this. the below code working fine.
SELECT CASE WHEN companyID in(select CompanyId from table2) THEN 1
ELSE 0
END AS dummy
FROM table1
You can use EXISTS
SELECT CASE
WHEN EXISTS(SELECT 1 FROM Table2 AS T2 WHERE T1.CompanyID = T2.CompanyID) THEN 1
ELSE 0
END AS Dummy
FROM Table1 AS T1;
If your DB's version is 2012+ then, use with left join as :
select t1.*, iif(#_of_Shareholders is null, 0, 1) as dummy
from table1 t1
left join table2 t2
on ( t1.CompanyID = t2.CompanyID );
else
select t1.*,
( case when #_of_Shareholders is null then 0 else 1 end )
as dummy
from table1 t1
left join table2 t2
on ( t1.CompanyID = t2.CompanyID );
or
select t1.*,
sign(coalesce(#_of_Shareholders,0))
as dummy
from table1 t1
left join table2 t2
on ( t1.CompanyID = t2.CompanyID );
Rextester Demo

How to make query to select data as I want

I have three tables.
Table1
item desc
1 item1
2 item2
3 item3
Table2:
item2 desc2
1 item1
2 item2
3 item3
Table3:
item1 item2 quantity
1 1 5
1 2 4
2 2 3
3 1 10
Now in table 3, column 1 (item1) is foreign key to Table1 and column 2 (item2) is foreign key to Table2. Now I want to write a query to fetch records like it crosss join all possible combination if some combination for some records does exist it shows their quantity 0 like this.
I want result like this:
item1 item2 quantity
1 1 5
1 2 4
1 3 0
2 2 3
2 1 0
2 3 0
3 1 10
3 2 0
3 3 0
Thanks.
Use cross join
select t1.item as Item1, t2.item as Item2, coalesce(t3.quantity, 0) as quantity
from table1 t1 cross join
table2 t2 left join
table3 t3
on t3.item1 = t1.item and t3.item2 = t2.item
order by t1.item, t3.quantity desc, t2.item;
Keep it simple :)
DB-Fiddle
SELECT t1.item, t2.item2, IFNULL(t3.quantity, 0) as quantity
FROM
t1 JOIN t2
LEFT JOIN t3 ON t3.item1 = t1.item AND t3.item2 = t2.item2
JOIN without ON -> joins everything to everything
LEFT JOIN adds data to rows (in this case quantity) but leaves rows intact
Assuming tables named #tab1, #tab2 and #tab3, you can do:
SELECT b.item, b.item2, IsNull(a.quantity, 0) as quantity
FROM (SELECT item, item2 FROM #tab1 CROSS APPLY #tab2) b
FULL OUTER JOIN #tab3 a ON a.item1 = b.item AND a.item2 = b.item2

SQL LEFT JOIN first row only

Let's assume we have such data set:
Table: DataTable1
ID ExperienceId LanguageId ...
-------------------------------------------
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 2 3
7 3 1
8 3 2
9 3 3
...
Table: DataTable2
ID SomeId OtherId LanguageId ...
-------------------------------------------
1 459 1 1
2 459 1 2
3 459 1 3
4 245 2 1
5 245 2 2
6 245 2 3
7 295 3 1
8 295 3 2
9 295 3 3
...
I want to join those tables and get only SomeId column ignoring the LanguageId column. To make it clearer:
SELECT
t2.SomeId AS RequiredId
-- ...other data mainly from t2
FROM DataTable1 AS t1
LEFT JOIN DataTable2 AS t2
ON t2.OtherId = t1.ExperienceId
AND t2.LanguageId =
(SELECT TOP 1 t1.LanguageId
ORDER BY t1.LanguageId)
This query should return (if it wasn't wrong, clearly) rows:
SomeId ...
----------------
459 ...
245 ...
295 ...
...
Now it returns three times of identical data (with only LanguageId different).
I would try to filter it with WHERE t1.LanguageId = 1 if I was sure it always exists, but I'm not sure. Rows can be with LanguageId from 1 to 3, also they can be only with ID 2, etc. Rows surely will have at least one LanguageId.
Now my question is: how can I join tables with unique values with one column completely ignored?
Wrapping it in another query does the trick?
SELECT RequiredId, <all_the_other_fields> from (
SELECT t2.SomeId AS RequiredId
-- ...other data mainly from t2
FROM DataTable1 AS t1
LEFT JOIN DataTable2 AS t2
ON t2.OtherId = t1.ExperienceId
AND t2.LanguageId =
(SELECT TOP 1 t1.LanguageId
ORDER BY t1.LanguageId)
) group by RequiredId, <all_the_other_fields>
or even not extracting the column in the first place?
SELECT distinct t2.SomeId AS RequiredId
-- ...other data mainly from t2 BUT not the Language id
FROM DataTable1 AS t1
LEFT JOIN DataTable2 AS t2
ON t2.OtherId = t1.ExperienceId
AND t2.LanguageId =
(SELECT TOP 1 t1.LanguageId
ORDER BY t1.LanguageId)
Try this:
;with cte as
(select *, row_number() over (partition by someid order by languageid) rn
from datatable2)
select *
from datatable1 dt
left join cte c on dt.experienceid = c.otherid and c.rn = 1
For such things when you need to select top in the subquery CROSS APPLY OR 'OUTER APPLY' is very handy
t2.SomeId AS RequiredId
-- ...other data mainly from t2
FROM DataTable1 AS t1
OUTER APPLY ( SELECT TOP 1 t1.LanguageId
FROM DataTable2
WHERE DataTable2 .OtherId = t1.ExperienceId
AND t2.LanguageId = t1.LanguageId
ORDER BY t1.LanguageId
) AS t2
Try this:
SELECT DISTINCT t2.SomeId AS RequiredId
-- ...other data mainly from t2
FROM DataTable1 AS t1
LEFT JOIN DataTable2 AS t2
ON t2.OtherId = t1.ExperienceId
WHERE t2.LanguageId = t1.LanguageId
Are you looking for this (Fiddle: http://sqlfiddle.com/#!3/811b8/12)?:
SELECT dt2.*
FROM DataTable1 dt1 INNER JOIN DataTable2 dt2
ON dt1.ExperienceID = dt2.OtherID AND
dt1.LanguageID = dt2.LanguageID
WHERE dt2.LanguageID = (SELECT MIN(LanguageID) FROM DataTable1);
produces:
ID SOMEID OTHERID LANGUAGEID
1 459 1 1
4 245 2 1
7 295 3 1

Design SQL Query for following case

Consider tables
Table1
id, name
1 xyz
2 abc
3 pqr
Table2
id title
1 Mg1
2 Mg2
3 SG1
Table3
Tb1_id tb2_id count
1 1 3
1 2 3
1 3 4
2 2 1
3 2 2
3 3 2
I want to do query to give result like
id title
1 MG1
2 MG2
3 Two or More Title
MG1 has higher preference if MG1 and count >= 1 then it is given as MG1 title , for others corresponding title is used and for count > 1 as two or more
I think this is what you are going for:
select t3.Tb1_id as id,
case
when mg1cnt.count >= 1 then 'MG1'
when cnt.count = 1 then upper(t2.title)
else 'Two or More Titles'
end as title
from (
select Tb1_id, count(*) as count
from Table3
group by Tb1_id
) cnt
inner join (
select Tb1_id, isnull(SUM(case when t2.title='mg1' then 1 end), 0) as count
from Table3 t3
inner join Table2 t2 on t3.tb2_id = t2.id
group by Tb1_id
) as mg1cnt on cnt.Tb1_id = mg1cnt.Tb1_id
inner join Table3 t3 on cnt.Tb1_id = t3.Tb1_id
inner join Table2 t2 on t3.tb2_id = t2.id
group by t3.Tb1_id,
case
when mg1cnt.count >= 1 then 'MG1'
when cnt.count = 1 then upper(t2.title)
else 'Two or More Titles'
end