Group by query with rollup - sql

I'm trying to make a query that shows me every region and then make a count to see how mano contracts I have per region, but somehow I'm getting an error on ROLLUP (BO2.area)
This is the query
SELECT
CASE WHEN BO2.area IS NULL THEN ISNULL(BO2.area, 'TOTAL') ELSE BO2.area END Area,
COUNT(BO.status = 'INSTALLED') Contracts
FROM
BO2
JOIN BO ON BO.bostamp = BO2.bo2stamp
GROUP BY
ROLLUP (BO2.area)

Should use GROUPING instead of a null check, and inside the aggregate you need a CASE expression. So:
SELECT
CASE WHEN GROUPING(BO2.area)=1 THEN 'TOTAL' ELSE BO2.area END Area,
SUM( CASE WHEN BO.status = 'INSTALLED' THEN 1 ELSE 0 END ) Contracts
FROM
BO2
JOIN BO ON BO.bostamp = BO2.bo2stamp
GROUP BY
ROLLUP (BO2.area)

your query fails because Area is number (I'm guessing) and you want to combine it to text , so you need to cast it to string:
SELECT
CASE WHEN GROUPING(BO2.area)=1 THEN (cast(BO2.area as varchar(100)),'TOTAL') ELSE BO2.area END as Area
, COUNT(CASE WHEN BO.status = 'INSTALLED' THEN 1 ELSE 0 END ) Contracts
FROM
BO2
JOIN BO ON BO.bostamp = BO2.bo2stamp
GROUP BY
ROLLUP (BO2.area)

Related

Having trouble with the subquery in this code

I'm trying to run this code for an assignment for a class I've got. The "x" at the end of my subquery keeps on giving me errors and I can't wrap my head around why this is.
The goal of this assignment is to count (by age group) the number of reports that Carditis was a symptom after receiving a COVID shot.
Thanks in advance
Select agegroup, sum(case when died= 'Y' then 1 else 0 end) as Deaths
From (Select *,
Case
when age<=2 then 'infant'
when age<18 then 'juvenile'
when age<35 then 'adult'
when age<65 then 'old adult'
when age>=65 then 'senior'
else 'unknown' end as agegroup
from dbo.symptoms as s
join dbo.vaersvax as v on s.vaers_id=v.vaers_id
join dbo.patient as p on s.vaers_id=p.vaers_id
where v.vax_type='COVID19' and OneVax='Y' and symptom='Carditis'
) as x
Group By agegroup
Order By avg(age)
As #Schmocken already said, you can't perform a SELECT FROM a subquery that returns more than one column with the same name. As I suppose from your external query, this would do the job for you:
Select agegroup, sum(case when died= 'Y' then 1 else 0 end) as Deaths
From (Select died, age,
Case
when age<=2 then 'infant'
when age<18 then 'juvenile'
when age<35 then 'adult'
when age<65 then 'old adult'
when age>=65 then 'senior'
else 'unknown' end as agegroup
from dbo.symptoms as s
join dbo.vaersvax as v on s.vaers_id=v.vaers_id
join dbo.patient as p on s.vaers_id=p.vaers_id
where v.vax_type='COVID19' and OneVax='Y' and symptom='Carditis'
) as x
Group By agegroup
Order By avg(age)
By using Select * you have specified the same column name to be returned more than once.
As an example, you are returning both s.vaers_id and v.vaers_id, which are the same. This is not allowed; a subquery must return a unique set of column names.
You could return s.* successfully, but not all columns from all tables.

Apply where clause within count in sql

SELECT
Rooms.Building,
Count(Rooms.Room) AS TotalApartments,
Count(Rooms.Room) AS ApartmentsOccupied
FROM
Rooms
WHERE
(((Rooms.AssetType) <> 'LC'))
GROUP BY
Rooms.Building;
I want to count Rooms.Room Where Rooms.Occupied = True (ApartmentsOccupied) but when I put this clause into my sql it also applies the where to the TotalApartments column
You can move some logic into CASE statements to do conditional summarization:
SELECT
Rooms.Building,
Count(Rooms.Room) AS TotalApartments,
Sum(CASE WHEN Rooms.Occupied = True THEN 1 ELSE 0 END) AS ApartmentsOccupied
FROM
Rooms
WHERE
(((Rooms.AssetType) <> 'LC'))
GROUP BY
Rooms.Building;
I'm not sure off the top of my head, but you might need to change that count to a SUM as well:
Sum(1) AS TotalApartments
And alternately, in some sql dialects the 'True' value is 1, so you could get away with something like this for the occupied count:
Sum(Rooms.Occupied) AS ApartmentsOccupied
You can do like this
SELECT
Building,
Count(Room) AS TotalApartments,
SUM(CASE WHEN Occupied = True THEN 1 ELSE 0 END) AS ApartmentsOccupied
FROM
Rooms
WHERE
AssetType <> 'LC'
GROUP BY
Building;

Select Categories and count the Ads inside

I want to make a query that select Categories name and count the max of Ads (active) in each category, I already did this:
SELECT
cat.cat_id,
cat.cat_desc,
COUNT(ad_id) AS cat_total_ads
FROM
tab_categories AS cat LEFT JOIN
tab_ads AS ads ON ads.cat_id = cat.cat_id
WHERE
cat_active = #cat_active AND
cat_deleted = #cat_deleted
GROUP BY
cat_desc, cat.cat_id
This query is counting the non active Ads too. How can I put the value 0 for the non active Ads?
One way to accomplish this is to use a combination of a CASE statement to determine if you want to count the item and the SUM function.
For example
SUM(CASE WHEN Active THEN 1 ELSE 0 END)
The SUM ( CASE ..... then 1 else 0 end ) as colName should do it for you !!
Try this i do not have the table to recreate to test but this or something similar should work.
select
cat.cat_id,
cat.cat_desc,
count(ad_id) as Total,
sum(case when ad_id= 0 then 1 else 0 end) as 'ad_id'
from
tab_categoriesAS cat LEFT JOIN
tab_ads AS ads ON ads.cat_id = cat.cat_id
WHERE
cat_active = #cat_active AND
cat_deleted = #cat_deleted
GROUP BY
cat_desc, cat.cat_id

How to do a SUM() inside a case statement in SQL server

I want to add some calculation inside my case statement to dynamically create the contents of a new column but I get the error:
Column 'Test1.qrank' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
This is the code I'm working on
case
when test1.TotalType = 'Average' then Test2.avgscore
when test1.TotalType = 'PercentOfTot' then (cnt/SUM(test1.qrank))
else cnt
end as displayscore
I did try to group but it didn't work.
Any hints?
The error you posted can happen when you're using a clause in the GROUP BY statement without including it in the select.
Example
This one works!
SELECT t.device,
SUM(case when transits.direction = 1 then 1 else 0 end) ,
SUM(case when transits.direction = 0 then 1 else 0 end) from t1 t
where t.device in ('A','B') group by t.device
This one not (omitted t.device from the select)
SELECT
SUM(case when transits.direction = 1 then 1 else 0 end) ,
SUM(case when transits.direction = 0 then 1 else 0 end) from t1 t
where t.device in ('A','B') group by t.device
This will produce your error complaining that I'm grouping for something that is not included in the select
Please, provide all the query to get more support.
You could use a Common Table Expression to create the SUM first, join it to the table, and then use the WHEN to to get the value from the CTE or the original table as necessary.
WITH PercentageOfTotal (Id, Percentage)
AS
(
SELECT Id, (cnt / SUM(AreaId)) FROM dbo.MyTable GROUP BY Id
)
SELECT
CASE
WHEN o.TotalType = 'Average' THEN r.avgscore
WHEN o.TotalType = 'PercentOfTot' THEN pt.Percentage
ELSE o.cnt
END AS [displayscore]
FROM PercentageOfTotal pt
JOIN dbo.MyTable t ON pt.Id = t.Id
If you're using SQL Server 2005 or above, you can use the windowing function SUM() OVER ().
case
when test1.TotalType = 'Average' then Test2.avgscore
when test1.TotalType = 'PercentOfTot' then (cnt/SUM(test1.qrank) over ())
else cnt
end as displayscore
But it'll be better if you show your full query to get context of what you actually need.

T-SQL Group By; Contains or IfAny

SQL2005 and/or SQL2008
Is there any kind of built-in aggregate, within T-SQL, for Contains or IfAny or whatever? Something where any in the group equals a value?
Similar to Max(xyz)=value except not limited to max.
Select custID, case when Min(ProductGroup)= "A" then 'Have Ordered Group A' else 'Haven't Ordered Group A' end hasOrdered
from orders
inner join products on ordPoductId = productID
group by custID
This works for a single value comparison, if it is min/max, but instead I want something like:
Select custID, case when contains(ProductGroup, "G") then 'Have Ordered Group G' else 'Haven't Ordered Group G' end hasOrdered
from orders
inner join products on ordPoductId = productID
group by custID
I could use Min(ProductGroup)="A" if the value I'm concerned about is a min/max or change the from-clause to (case when 'G' then 0 else 1 end) to create a fake maximum. Currently I am only concerned with a single value, but I would like something more intuitive and flexible if possible.
Any ideas?
Your examples at the end are close to what I'd normally do. Something like:
CASE MAX(CASE WHEN ProductGroup = 'G' THEN 1 ELSE 0 END)
WHEN 1 THEN 'Have Ordered'
ELSE 'Haven''t ordered'
END
Where the inner CASE expression will obviously be evaluated against each row, whereas the outer CASE expression determines whether the inner expression ever succeeded.