Below is my sample code situation
declare #Ka int = select count(empid) from employee where age between 18 and 22
declare #Kb int = select count(empid) from employee where age between 23 and 30
declare #Kc int = select count(empid) from employee where age between 31 and 35
Now, If Ka/Kb/Kc has some value other than 0 or null then it should display 'x' and if not it should display blank. So my select statement is:
select
CASE WHEN #Ka = 0 then ''
ELSE 'X'
END AS 'Ka',
CASE WHEN #Kb = 0 then ''
ELSE 'X'
END AS 'Kb',
CASE WHEN #Kc = 0 then ''
ELSE 'X'
END AS 'Kc'
So If I have around more parameters, should I do a case statement for each parameter as above? Is there a way to do single case statement including all the parameters obeying the condition? Or is there a simple way to accomplish something similar to this?
Why do it this way? It seems much more efficient if you were to do the following (without variables):
SELECT CASE WHEN COUNT(CASE WHEN age BETWEEN 18 AND 22 THEN empid END) = 0 THEN '' ELSE 'X' END AS Ka,
CASE WHEN COUNT(CASE WHEN age BETWEEN 23 AND 30 THEN empid END) = 0 THEN '' ELSE 'X' END AS Kb,
CASE WHEN COUNT(CASE WHEN age BETWEEN 31 AND 35 THEN empid END) = 0 THEN '' ELSE 'X' END AS Kc
FROM Employee;
No. Don't do this. You need the logic inside the query:
select sum(case when age between 18 and 22 then 1 else 0 end) as age_18_22,
sum(case when age between 23 and 30 then 1 else 0 end) as age_23_30,
sum(case when age between 31 and 35 then 1 else 0 end) as age_31_35
from employee e;
SQL doesn't work by substituting text in query strings. I mean, you can do that -- it is called dynamic sql. But you should first learn the basics of expressing queries.
Related
is that anyway to write similar query without using union?
select sum(decode(p.sumsend,0,1,0)) recvcnt,
sum(decode(p.sumsend,0,1,0)*p.sumserv) recvsum
from some_table p
where p.polefilter = 5
union
select sum(decode(p.sumsend,0,1,0)) recvcnt,
sum(decode(p.sumsend,0,1,0)*p.sumserv) recvsum
from some_table p
where p.polefilter != 5
If you are OK with having all 4 columns on one row, then one option is conditional aggregation:
select
sum(case when polefilter = 5 and sumsend = 0 then 1 else 0 end) recvcnt1,
sum(case when polefilter = 5 and sumsend = 0 then 1 else 0 end * sumserv) recvsum1,
sum(case when polefilter <> 5 and sumsend = 0 then 1 else 0 end) recvcnt2,
sum(case when polefilter <> 5 and sumsend = 0 then 1 else 0 end * sumserv) recvsum2
from some_table p
where polefilter is not null
On the other hand, if you want two rows in the resultset, then you can use aggregation and a case expression to define the groups:
select
case when polefilter = 5 then 1 else 0 end as polefilter_is_5
sum(case when sumsend = 0 then 1 else 0 end) recvcnt,
sum(case when sumsend = 0 then 1 else 0 end * sumserv) recvsum1
from some_table p
where p.polefilter is not null
group by case when polefilter = 5 then 1 else 0 end
Note that I changed the decode() functions to case expressions; both do the same thing, but the latest is standard SQL (and is somehow more flexible).
A query like the one below should work. Please provide sample data and expected output when asking a question next time.
SELECT SUM (CASE WHEN p.sumsend = 0 THEN 1 ELSE 0 END) recvcnt,
SUM (CASE WHEN p.sumsend = 0 THEN 1 ELSE 0 END * p.sumserv) recvsum
FROM some_table p
GROUP BY CASE p.polefilter WHEN 5 THEN 1 ELSE 0 END;
I have a table like this:
user_id, gender, sent
1 M 100
1 F 120
2 M 20
2 F 30
I want a table like this from the above:
user_id, male_sent, female_sent, total_sent
1 100 120 220
2 20 30 50
I lack the (Postgres) SQL foo to figure this one out.
You can use an aggregate function with a CASE expression to get the result:
select user_id,
sum(case when gender = 'M' then sent else 0 end) male_sent,
sum(case when gender = 'F' then sent else 0 end) female_sent,
sum(sent) total_sent
from yourtable
group by user_id
See SQL Fiddle with Demo
What database are you using?
If you are using SQL Server, you could do something like this:
SELECT user_id,sum(case when gender = 'M' then sent else 0 end) as male_sent,
sum(case when gender = 'F' then sent else 0 end) as female_sent,
sum(sent) as total_sent
FROM your_table_name
GROUP BY user_id
I have a table tbl_marksObtained that contains the following data:
stdID sub marks_Obtained
201bct2007 computer 45
201bct2007 Drawing 0
202bct2007 computer 0
203bct2007 Drawing 65
.
230bct2007 computer 77
301bct2008 physics 0
301bct2008 computer 55
.
.
401bct2009 and so on..
Now I would like to display the results as:
year sub pass fail
2007 computer 20 10
2007 Drawing 15 15
2008 computer 28 2
2009 computer 20 10
I obtained the pass fail of particular year and subject by following code:
SELECT
SUM( CASE WHEN marks_obtained > '0' THEN 1 END) AS pass,
SUM( CASE WHEN marks_obtained = '0' THEN 1 END) AS fail
FROM
tblstudentexammarks
WHERE
sub ='computer' AND stdID LIKE '%bce2007'
but how will I get the above results year wise data
select
RIGHT(stdID,4) as year,
sub,
sum(CASE WHEN marks_Obtained>0 then 1 else 0 end) as pass,
sum(CASE WHEN marks_Obtained=0 then 1 else 0 end) as fail
from tblstudentexammarks
group by RIGHT(stdID,4),sub
order by 1
try this:
select stdID [Year],sub,
sum(case when PF='P' then 1 else 0 end) as Pass,
sum(case when PF='F' then 1 else 0 end) as Fail
from(
select RIGHT(stdID,4) stdID,sub,
case when marks_Obtained=0 then 'F' else 'P' end PF
from mark_sheet)a
WHERE
sub ='computer' AND stdID LIKE '%bce2007'
group by stdID,sub
please consider this image:
I have a table like this:
Age Active Men/Women
-------------------------------------------------
I want to write a query that calulate Count of every age intervals for men and women.I don't know How I can use GROUP BY and intervals.
in my reports in left side of above image I want to calculate UnActive rows.How I can merge this to query to one query?
thanks
SELECT
Active.State,
Age.Base, Age.Base+4,
COUNT(*) AS TotalCount,
COUNT(CASE WHEN T.[Men/Women] = 'man' THEN 1 END) AS ManCount,
COUNT(CASE WHEN T.[Men/Women] = 'woman' THEN 1 END) AS WomanCount
FROM
(
VALUES (10),(15),(20),(25),(30),(35),(40) /*.. add the rest */,(90),(95)
) AS Age(base)
CROSS JOIN
(
VALUES (0), (1)
) AS Active(State)
LEFT JOIN
MyTable T ON T.Age BETWEEN Age.Base AND Age.Base+4 AND T.Active = Active.State
GROUP BY
Active.State,
Age.Base, Age.Base+4;
After this, you can format it how you want
Edited to generate empty ranges
You can GROUP BY on age interval CASEs:
SELECT
COUNT(*) AGE_COUNT,
CASE WHEN AGE BETWEEN 15 AND 19 THEN 'Age 15-19'
WHEN AGE BETWEEN 20 AND 24 THEN 'Age 20-24'
ELSE 'Other'
END AGE_INTERVAL
FROM
YOUR_TABLE
GROUP BY
CASE WHEN AGE BETWEEN 15 AND 19 THEN 'Age 15-19'
WHEN AGE BETWEEN 20 AND 24 THEN 'Age 20-24'
ELSE 'Other'
END
This should work:
SELECT SUM(CASE WHEN [Men/Women] = 'M' THEN 1 ELSE 0 END) AS Men,
SUM(CASE WHEN [Men/Women] = 'W' THEN 1 ELSE 0 END) AS Women,
COUNT(*) as Total,
CASE WHEN Age BETWEEN 10 AND 14 THEN 'Age 10-14'
WHEN Age BETWEEN 15 AND 19 THEN 'Age 15-19'
WHEN Age BETWEEN 20 AND 24 THEN 'Age 20-24'
ELSE 'Old'
END Age
FROM MyTable
WHERE Active = 1
GROUP BY CASE WHEN Age BETWEEN 10 AND 14 THEN 'Age 10-14'
WHEN Age BETWEEN 15 AND 19 THEN 'Age 15-19'
WHEN Age BETWEEN 20 AND 24 THEN 'Age 20-24'
ELSE 'Old'
END
You can actually expand on from what Andrea provided...
SELECT
CASE WHEN YT.AGE BETWEEN 15 AND 19 THEN 'Age 15-19'
WHEN YT.AGE BETWEEN 20 AND 24 THEN 'Age 20-24'
ELSE 'Other'
END AGE_INTERVAL,
SUM( CASE WHEN YT.Active THEN 1 ELSE 0 END ) as ActiveCount,
SUM( CASE WHEN YT.Gender = 'M' THEN 1 ELSE 0 END ) as MaleCount,
SUM( CASE WHEN YT.Gender = 'F' THEN 1 ELSE 0 END ) as FemaleCount,
COUNT(*) AgeGroupCount
FROM
YourTable YT
GROUP BY
Age_Interval
As others have mentioned this is trying to report on a way that is not the same as your data at all.
But I think the best way achieve this within SQL is to create a scalar function (props to #gbn for the min/max age range logic):
CREATE FUNCTION usvf_calculate_age_bracket
(
-- Add the parameters for the function here
#age INT
)
RETURNS VARCHAR(50)
AS
BEGIN
-- Return the result of the function
RETURN CAST(#age/5*5 AS VARCHAR(20)) + '-' + CAST(#age/5*5+4 AS VARCHAR(20))
END
GO
Then in your query you can do:
SELECT SUM(CASE WHEN gender = 'F' THEN active ELSE 0 END) AS [Women],
SUM(CASE WHEN gender = 'M' THEN active ELSE 0 END) AS [Men],
SUM(CAST(active AS int)) AS [Total],
'Age ' + dbo.usvf_calculate_age_bracket(age) AS [Age]
FROM myTable
GROUP BY dbo.usvf_calculate_age_bracket(age)
My test code:
DECLARE #T TABLE
(
age int,
active bit,
gender char(1)
)
INSERT INTO #T VALUES (25, 1, 'M'),(32, 0, 'F'),(21, 1, 'M'),(22, 1, 'F'),(28, 1, 'F'),(32, 0, 'M'), (23, 1, 'M'),(42, 0, 'F'),(29, 1, 'M'),(29, 1, 'F'),(28, 1, 'F'),(32, 1, 'M')
SELECT SUM(CASE WHEN gender = 'F' THEN active ELSE 0 END) AS [Women],
SUM(CASE WHEN gender = 'M' THEN active ELSE 0 END) AS [Men],
SUM(CAST(active AS int)) AS [Total],
'Age ' + dbo.usvf_calculate_age_bracket(age) AS [Age] FROM #T
GROUP BY dbo.usvf_calculate_age_bracket(age)
Results:
Women Men Total Age
1 2 3 Age 20-24
3 2 5 Age 25-29
0 1 1 Age 30-34
0 0 0 Age 40-44
Which seems to be close to what you want, and it isn't an overly complicated SQL query to achieve this. (except I can't work out your 'total' column)
I'm trying to write a query that gives me a percentage (i.e. something like .885, for example) by dividing 2 aggregate numbers I selected via SUM. But my results are coming out as 0.0 instead of the correct number. So just for reference, starting with 2 queries, I have:
SELECT SUM(CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END)
FROM SomeTable
Which yields 158. And:
SELECT SUM(CASE WHEN State_ID = 14 THEN 1 ELSE 0 END)
FROM SomeTable
Yields 203.
Now, if I were to do just this:
SELECT SUM(CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END)/SUM(CASE WHEN State_ID = 14 THEN 1 ELSE 0 END)
FROM SomeTable
I would get 0, because everything is being used as integers. So I tried this:
SELECT CAST(SUM(CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END)/SUM(CASE WHEN State_ID = 14 THEN 1 ELSE 0 END) AS DECIMAL(3,1))
FROM SomeTable
But my result is 0.0. And this is obviously not what I'd like. I'd like to be getting .778
I'm thinking that I need to be casting the numbers individually, but I tried that and got an arithmetic overflow exception. Does anyone see what I could be doing differently?
I'm using SQL Server 2005. Thanks very much.
what happens when you do
THEN 1.0 ELSE 0.0
you can also cast each number that you are dividing, there is no point casting the sum
see also
select 3/2 --1
select 3/2.0 --1.500000
select 3/convert(decimal(3,2),2) --1.500000
So this is one way
SELECT SUM(convert(decimal(3,2),
CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END))/
SUM(convert(decimal(3,2),CASE WHEN State_ID = 14 THEN 1 ELSE 0 END))
To handle division by 0 do this
SELECT CASE SUM(convert(decimal(3,2),CASE WHEN State_ID = 14 THEN 1 ELSE 0 END))
when 0 then 0 else SUM(convert(decimal(3,2),
CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END))/
SUM(convert(decimal(3,2),CASE WHEN State_ID = 14 THEN 1 ELSE 0 END)) END
See also here: SQL Server efficient handling of divide by zero
You had the right idea, you just didn't go far enough with it.
SELECT CAST(SUM(CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END) AS DECIMAL(3,1))/CAST(SUM(CASE WHEN State_ID = 14 THEN 1 ELSE 0 END) AS DECIMAL(3,1))
FROM SomeTable
Your expression is doing the integer division and then converting to decimal. You have to change the expression so that it does the division as decimal. Setting the constants as decimals (1.0, 0.0) or casting at least one integer as decimal should avoid the problem.