Get record ids from groups where the sum of one of the field of their records is greater than - sql

I have records as such:
Id ForeignKey Level ValueA ValueB
1 1001 1 2 10
2 1001 1 10 10
3 1001 1 20 20
4 1001 2 20 30
5 1002 1 1 100
6 1003 1 1 100
7 1004 1 1 100
I want to get the Ids of each record of the groups grouped by ForeignKey and Level where the sum of the group's records' ValueA values divided by the sum of ValueB values is greater than 0.5
In this case, I'd like to retrieve the Id of the three first records as (2 + 10 + 20) / (10 + 10 + 20) = 0.8
Here is what I've got so far:
select
ForeignKey,
SUM(ValueA) as ValueASum,
SUM(ValueB) as ValueBSum,
from tableA
group by ForeignKey
having (SUM(ValueA) / SUM(ValueB) > 0.5)
The result is
ForeignKey ValueASum ValueBSum
1001 32 40
How do I get the ids of the records from this point? If I add the Id in the select, I must group on it and then have a group for each record.
Thanks for your time

Hm, how about
select id from your_table where foreignkey = 1001
Is something wrong with working with multiple queries?
If you want you can do a subquery:
select id from your_table where foreignkey in ( select foreignkey from ( <yourQuery> ) sq);
UPDATE:
select t.id from Table1 t
inner join
(
select
ForeignKey, level,
SUM(ValueA) as ValueASum,
SUM(ValueB) as ValueBSum
from Table1
where level = 1
group by ForeignKey, Level
having (SUM(ValueA) / SUM(ValueB) > 0.5) ) sq
ON t.foreignkey = sq.foreignkey AND t.level = sq.level
I added where level = 1 just because your given resultset not what I get when I execute your query.
See it working live in an sqlfiddle.

You were on the right track, but if you wanted it from each "Level", you would need to add that into your group by also.
select
tA2.ID,
tA2.ForeignKey,
tA2.Level,
tA2.ValueA,
tA2.ValueB
from
( select
tA.ForeignKey,
tA.Level,
SUM(tA.ValueA) as ValueASum,
SUM(tA.ValueB) as ValueBSum,
from
tableA tA
group by
tA.ForeignKey,
tA.Level
having
(SUM(tA.ValueA) / SUM(tA.ValueB) > 0.5) ) PreQualified
JOIN tableA tA2
on PreQualified.ForeignKey = tA2.ForeignKey
AND PreQualified.Level = tA2.Level
This would give all values that matched the qualifying condition.

Related

SQL left join with 2 or more count group

My table
ID catone cattwo
100 2 1
100 3 1
200 1 2
expect result (count not sum)
ID totalcat1 totalcat2
100 2 2
200 1 1
My query
select COUNT(*) as totalcat1, catone
from Table1
group by cat1
left join
select COUNT(*) as totalcat2, cattwo
from Table1
group by cattwo
Try to have both count columns catone and cattwo
Not sure how to correct it. Thank you
A simple group-by should do it
select ID, COUNT(catone) as totalcat1, COUNT(cattwo) as totalcat2
from Table1
group by ID;
Note that this simply counts the number of values that are not NULL. If your original data was this...
ID catone cattwo
100 2 1
100 3 1
100 4 NULL
... then the result would be
ID totalcat1 totalcat2
100 3 2
If you want to count the distinct values - so totalcat2 would be 1 (as only 1 value exists in that column, although it's there twice) you could use
select ID, COUNT(DISTINCT catone) as totalcat1, COUNT(DISTINCT cattwo) as totalcat2
from Table1
group by ID;
which would return totalcat1 = 3 and totalcat2 = 1.
Here's a db<>fiddle with the two options.
Here's a second db<>fiddle on request of OP with ID 200.

SQL join query for a view with sum of columns across 3 tables

I have 3 tables as below
Table - travel_requests
id industry_id travel_cost stay_cost other_cost
1 2 1000 500 200
2 4 4000 100 200
3 5 3000 0 400
4 1 3000 250 100
5 1 200 100 75
Table - industry_tech_region
id industry_name
1 Auto
2 Aero
3 Machinery
4 Education
5 MTV
Table - industry_allocation
id industry_id allocation
1 1 500000
2 2 300000
3 3 500000
4 4 300000
5 5 500000
6 1 200000
I want to create a view which has 3 columns
industry_name, total_costs, total_allocation
I created a view as below
SELECT industry_tech_region.industry_name,
SUM(travel_requests.travel_cost + travel_requests.stay_cost + travel_requests.other_cost) AS total_cost,
SUM(industry_allocation.allocation) AS total_allocation
FROM industry_tech_region
INNER JOIN industry_allocation
ON industry_tech_region.id = industry_allocation.industry_id
INNER JOIN travel_requests
ON industry_tech_region.id = travel_requests.industry_id
GROUP BY industry_tech_region.industry_name
But the result I get is as below which is incorrect
industry_name total_cost total_allocation
Aero 1700 300000
Auto 7450 1400000 (wrong should be 3725 and 700000)
Education 4300 300000
MTV 3400 500000
This is probably happening because there are 2 entries for industry_id 1 in the travel_requests table. But they should be counted only once.
Please let me know how do we correct the view statement.
Also I want to add another column in view which is remaining_allocation which is difference of total_allocation and total_cost for each industry.
you shoud join the sum (and not sum the join)
select
a.industry_name
, t1.total_cost
, t2.total_allocation
from dbo.industry_tech_region a
left join (
select dbo.travel_requests.industry_id
, SUM(dbo.travel_requests.travel_cost + dbo.travel_requests.stay_cost + dbo.travel_requests.other_cost) AS total_cost
FROM bo.travel_requests
group by dbo.travel_requests.industry_id
) t1 on a.id = t1.industry_id
left join (
select dbo.industry_allocation.industry_id
, SUM(dbo.industry_allocation.allocation) AS total_allocation
from dbo.industry_allocation
group by dbo.industry_allocation.industry_id
) t2 on a.id = t2.industry_id
this happen because you have two entry for the industry_id 1 and then the row are joined two time if you use the subquery for aggreated the row this can't happen ...
I have used left join because seems that not all the industry_id match for the 3 tables ..
You can use this approach too (without the ORDER BY because views do not allow it).
;WITH q AS (
SELECT industry_id
, sum(allocation) AS total_allocation
FROM #industry_allocation
GROUP BY industry_id
)
SELECT #industry_tech_region.industry_name
, isnull(SUM(#travel_request.travel_cost
+ #travel_request.stay_cost
+ #travel_request.other_cost),0.0) AS total_cost
,q.total_allocation AS total_allocation
FROM #industry_tech_region
LEFT JOIN q ON #industry_tech_region.id = q.industry_id
LEFT JOIN #travel_request ON #industry_tech_region.id = #travel_request.industry_id
GROUP BY #industry_tech_region.industry_name,q.total_allocation
ORDER BY industry_name

select query - eliminate rows with duplicate column value on condition

I have a select query that ends up with results like:
ID COMPLIANT
------------------
10 0
12 0
29 0
29 1
43 1
44 1
44 0
How can I get results without these duplicate ID rows, on the condition that if an ID has already been marked as COMPLIANT once (a 1 instead of a 0), the duplicate rows with COMPLIANT=0 do not appear? I'd want:
ID COMPLIANT
------------------
10 0
12 0
29 1
43 1
44 1
How about aggregation?
select id, max(complaint) as complaint
from t
group by id;
This returns one row per id. If you can have multiple complaints -- and you want all of those -- than an alternative is:
select id, complaint
from t
where complaint = 1
union all
select id, complaint
from t
where not exists (select 1 from t t2 where t2.id = t.id and t2.complaint = 1);
this will work:
select id, max(complaint)
from tablename
group by id;

How to declare a row as a Alternate Row

id Name claim priority
1 yatin 70 5
6 yatin 1 10
2 hiren 30 3
3 pankaj 40 2
4 kavin 50 1
5 jigo 10 4
7 jigo 1 10
this is my table and i want to arrange this table as shown below
id Name claim priority AlternateFlag
1 yatin 70 5 0
6 yatin 1 10 0
2 hiren 30 3 1
3 pankaj 40 2 0
4 kavin 50 1 1
5 jigo 10 4 0
7 jigo 1 10 0
It is sorted as alternate group of same row.
I am Using sql server 2005. Alternate flag starts with '0'. In my example First record with name "yatin" so set AlternateFlag as '0'.
Now second record has a same name as "yatin" so alternate flag would be '0'
Now Third record with name "hiren" is single record, so assign '1' to it
In short i want identify alternate group with same name...
Hope you understand my problem
Thanks in advance
Try
SELECT t.*, f.AlternateFlag
FROM tbl t
JOIN (
SELECT [name],
AlternateFlag = ~CAST(ROW_NUMBER() OVER(ORDER BY MIN(ID)) % 2 AS BIT)
FROM tbl
GROUP BY name
) f ON f.name = t.name
demo
You could use probably an aggregate function COUNT() and then HAVING() and then UNION both Table, like:
SELECT id, A.Name, Claim, Priority, 0 as AlternateFlag
FROM YourTable
INNER JOIN (
SELECT Name, COUNT(*) as NameCount
FROM YourTable
GROUP BY Name
HAVING COUNT(*) > 1 ) A
ON YourTable.Name = A.Name
UNION ALL
SELECT id, B.Name, Claim, Priority, 1 as AlternateFlag
FROM YourTable
INNER JOIN (
SELECT Name, COUNT(*) as NameCount
FROM YourTable
GROUP BY Name
HAVING COUNT(*) = 1 ) B
ON YourTable.Name = B.Name
Now, this assumes that the Names are unique meaning the names like Yatin for example although has two counts is only associated to one person.
See my SqlFiddle Demo
You can use Row_Number() function with OVER that will give you enumeration, than use the reminder of integer division it by 2 - so you'll get 1s and 0s in your SELECT or in the view.

Update column value of one row from other rows

I have the following table:
sno name pid amount total
1 Arif 0 100 null
2 Raj 1 200 null
3 Ramesh 2 100 null
4 Pooja 2 100 null
5 Swati 3 200 null
6 King 4 100 null
I want total of each person such that it gives total sum of amount of its descendants.
For ex.
for RAJ total will be : total= amount of(raj+ramesh+pooja+swati+king)
for SWATI :Total=amount of swati only.
You could try something like this:
WITH hierarchified AS (
SELECT
sno,
amount,
hierarchyID = CAST(sno AS varchar(500))
FROM yourTable
WHERE pid = 0
UNION ALL
SELECT
t.sno,
t.amount,
hierarchyID = CAST(h.hierarchyID + '/' + RTRIM(t.sno) AS varchar(500))
FROM yourTable t
INNER JOIN hierarchified h ON t.pid = h.sno
)
UPDATE yourTable
SET total = t.amount + ISNULL(
(
SELECT SUM(amount)
FROM hierarchified
WHERE hierarchyID LIKE h.hierarchyID + '/%'
),
0
)
FROM yourTable t
INNER JOIN hierarchified h ON t.sno = h.sno;
Note that this query (which you can try on SQL Fiddle) would probably not be very efficient on a large dataset. It might do as a one-off query, and then it would likely be better to organise updating the totals each time the table is updated, i.e. using triggers.