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
Related
I have a pretty complex query I need to do which requires data from 6 different tables. The tables look like this:
Table 1
id
name
1
first_row
Table 2
id
table1_id
count
1
1
3
2
1
5
3
1
8
Table 3
id
table1_id
1
1
2
1
Table 4
id
table3_id
count
1
1
2
2
2
4
Table 5
id
table4_id
count
Table 6
id
table5_id
count
status
And I basically want to collect the count and sums from each of the table into 1 row such as:
Result
table1_id
table1_name
SUM(table2_count)
SUM(table4_count)
SUM(table5_count)
SUM(case when table6.status = 3 THEN 1 ELSE NULL END)
SUM(case when table6.status != 3 THEN 1 ELSE NULL END)
Tables 5 and 6 are empty
This is the latest thing I have tried, I hope it is clear:
SELECT table1.*, COUNT(distinct tbl3.id), SUM(table2.count::int), (SUM(table2.count::int) - SUM(table4.count::int))
, COUNT(table5.count), COUNT(table6.count)
FROM table1
LEFT JOIN table2
ON (table1.id = table2.table1_id AND table2.deleted_at IS NULL)
LEFT JOIN (
SELECT distinct table3.id, table3.table1_id, table3.deleted_at,
SUM(table4.total_count::int),
COUNT(case when table6.status != 3 THEN 1 ELSE NULL END),
COUNT(case when table6.status = 3 THEN 1 ELSE NULL END)
FROM table3
LEFT JOIN table4 ON (table3.id = table4.visa_id AND table4.deleted_at IS NULL)
LEFT JOIN (
SELECT table5.id, table5.table4_id,
COUNT(case when table6.status != 3 THEN 1 ELSE 0 END),
COUNT(case when table6.status = 3 THEN 1 ELSE 0 END)
FROM table5
LEFT JOIN table6 ON (table5.id = table6.table5_id AND table6.deleted_at IS NULL)
GROUP BY 1
) tbl3 ON table4.id = table5.table4_id
WHERE table2.deleted_at IS NULL
GROUP BY 1
) tbl2 ON (table1.id = tbl2.table1_id AND tbl2.deleted_at IS NULL);
The result I get based on the data added on top and the above query:
table1_id
table1_name
SUM(table2_count)
SUM(table4_count)
SUM(table5_count)
SUM(case when table6.status = 3 THEN 1 ELSE NULL END)
SUM(case when table6.status != 3 THEN 1 ELSE NULL END)
1
first_row
3
32
18
2
2
I do not get any errors but all the count come out wrong, either doubled or tripled and sometimes completely wrong (not even just doubled or something).
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;
I have two tables similar to:
Table 1 --unique ID's
ID Date
1 3/8/2017
2 3/8/2017
3 3/8/2017
Table 2
ID Date SourceID
1 3/8/2017 1
1 3/8/2017 2
1 3/8/2017 3
2 3/8/2017 2
3 3/8/2017 1
3 3/8/2017 3
And I want to write a query that has a result like:
Result
ID SourceID
1 2
2 2
3 1
Where the source ID ordering should be 2, 1, 3
I have:
select Table1.ID
, COALESCE(Join1.SourceID, Join2.SourceID, Join3.SourceID) as SourceID
from Table1
left outer join Table2 Join1
on Table1.date = Join1.date
and Table1.ID = Join1.ID
and Join1.SourceID = 2
left outer join Table2 Join2
on Table1.date = Join2.date
and Table1.ID = Join2.ID
and Join2.SourceID = 1
and Join1.SourceID is null
left outer join Table2 Join3
on Table1.date = Join3.date
and Table1.ID = Join3.ID
and Join3.SourceID = 3
and Join1.SourceID is null
and Join2.SourceID is null
But this currently just keeps the records where sourceid = 2 and does not add in the other sourceid's.
Thanks in advance for any help. Let me know if you need any clarification. Using SQL-Server. I only need a few and fixed amount of sources so I am avoiding using a cursor.
This is a prioritization query. I would do it using outer apply:
select t1.*, t2.sourceId
from table1 t1 outer apply
(select top 1 t2.*
from table2 t2
where t2.id = t1.id and t2.date = t1.date
order by (case t2.sourceid when 2 then 1 when 1 then 2 when 3 then 3 end)
) t2;
Note: For readability, you can simplify the order by to:
order by charindex(cast(t2.sourceId as varchar(255)), '2,1,3')
If you are uncomfortable with outer apply, you can do the same thing with a single join:
select t1.*, t2.sourceId
from table1 t1 join
(select t2.*,
row_number() over (partition by id, date
order by (case t2.sourceid when 2 then 1 when 1 then 2 when 3 then 3 end)
) as seqnum
from table2 t2
) t2
on t2.id = t1.id and t2.date = t1.date and t2.seqnum = 1;
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
I'm trying to set the date field for column date to let's say '10/11/2012' in table 1 when the sum of all amounts table 2 related to that id (via fk_id) = 0. Here's what I mean:
FROM:
table 1
id date
1 10/11/2011
2
3 10/12/2011
table 2
fk_id amount
1 200
2 0
2 0
3 100
TO:
table 1
id date
1 10/11/2011
2 10/11/2012
3 10/12/2011
table 2
fk_id amount
1 200
2 0
2 0
3 100
This is what I have currently:
update table1
set date = '10/11/2012
FROM table1 inner join table 2 on table1.id = table2.fk_id
HAVING sum(table2.amount) = 0
Can someone help me out here?
UPDATE table1
SET date = '10/11/2012'
FROM table1
WHERE id IN (SELECT FK_ID FROM table2 GROUP BY FK_ID HAVING SUM(Amount)=0)
This should work:
UPDATE T1
SET [date] = '20121011'
FROM table1 T1
INNER JOIN (SELECT fk_id, SUM(amount) Amount
FROM table2
GROUP BY fk_id
HAVING SUM(amount) = 0) T2
ON T1.id = T2.fk_id