I have following 3 select queries which returns 2 columns set.
Is there any way that quizno, correct, wrong and notattempted columns come at once like following:
quizno correct wrong notattempted
1 80 10 10
2 60 20 20
3 100 0 0
These are the separated queries:
select quizno, count(*) as correct from v_t1 where examid=96 AND result='correct'
group by quizno order by count(*) desc
select quizno, count(*) as wrong from v_t1 where examid=96 AND result='wrong'
group by quizno order by count(*) desc
select quizno, count(*) as notattempted from v_t1 where examid=96 AND result='notattempted'
group by quizno order by count(*) desc
you can use CASE aggregation and get the expected output
select quizno,
sum( case when result='correct' then 1 else 0 end) as 'correct',
sum( case when result='wrong' then 1 else 0 end) as 'wrong',
sum( case when result='notattempted' then 1 else 0 end) as 'notattempted'
from v_t1
where examid = 96
group by quizno
Related
Tried code:
SELECT count(*) Count_people_inside_3miles
FROM CLIENT_DATA
WHERE (ABS(C_ADD_X) >=1 AND ABS(C_ADD_X) <=3) AND (ABS(C_ADD_Y) >=1 AND ABS(C_ADD_Y) <=3);
SELECT count(CLIENT_ID) Count_Total_people
FROM CLIENT_DATA;
Result:
COUNT_PEOPLE_INSIDE_3MILES
15
COUNT_TOTAL_PEOPLE
24
How do I calculate 15/24*100?
Use conditional aggregation to do it all in a single table scan:
SELECT COUNT(
CASE
WHEN ABS(C_ADD_X) BETWEEN 1 AND 3 AND ABS(C_ADD_Y) BETWEEN 1 AND 3
THEN 1
END
) / COUNT(*) * 100 AS percentage_people_inside_3miles
FROM CLIENT_DATA;
I have a table which looks like shown below
ID SubmittedValue ApprovedValue
1 25.9 0
1 29 29
1 25.9 25.9
1 50 0
1 45 0
1 10 0
1 10 10
Expected result
ID SubsequentlyApproved(CNT) Total_Amt_sub_aprvd
1 2 35.9
We get the above result because 25.9+10 since it is repeated in the subsequent rows.
How to perform VLOOKUP like functionality for this scenario. I tried the subquery but it didn't work.
SELECT a.id,
SUM(CASE WHEN a.ApprovedValue=0 THEN 1 ELSE 0 END) AS SUB_COUNT
FROM myTable a
join (select id, sum( case when SubmittedValue=ApprovedValue then 1 end) as check_value from myTable) b
on b.id=a.id and SUB_COUNT=check_value
but this is not giving me the expected result.
You seem to want to count rows where the values are the same and the first value appears more than once. If so, you can use window functions and aggregation:
select id, count(*), sum(ApprovedValue)
from (select t.*, count(*) over (partition by id, SubmittedValue) as cnt
from t
) t
where cnt > 1 and SubmittedValue = ApprovedValue
group by id
Without window functions using a semi-join
select id, count(*), sum(submittedvalue)
from test t1
where submittedvalue=approvedvalue
and exists (select 1
from test t2
where t1.id=t2.id and t1.submittedvalue=t2.submittedvalue
group by id, submittedvalue
having count(*)>1)
group by id;
I have a table that has values and group ids (simplified example). I need to get the average for each group of the middle 3 values. So, if there are 1, 2, or 3 values it's just the average. But if there are 4 values, it would exclude the highest, 5 values the highest and lowest, etc. I was thinking some sort of window function, but I'm not sure if it's possible.
http://www.sqlfiddle.com/#!11/af5e0/1
For this data:
TEST_ID TEST_VALUE GROUP_ID
1 5 1
2 10 1
3 15 1
4 25 2
5 35 2
6 5 2
7 15 2
8 25 3
9 45 3
10 55 3
11 15 3
12 5 3
13 25 3
14 45 4
I'd like
GROUP_ID AVG
1 10
2 15
3 21.6
4 45
Another option using analytic functions;
SELECT group_id,
avg( test_value )
FROM (
select t.*,
row_number() over (partition by group_id order by test_value ) rn,
count(*) over (partition by group_id ) cnt
from test t
) alias
where
cnt <= 3
or
rn between floor( cnt / 2 )-1 and ceil( cnt/ 2 ) +1
group by group_id
;
Demo --> http://www.sqlfiddle.com/#!11/af5e0/59
I'm not familiar with the Postgres syntax on windowed functions, but I was able to solve your problem in SQL Server with this SQL Fiddle. Maybe you'll be able to easily migrate this into Postgres-compatible code. Hope it helps!
A quick primer on how I worked it.
Order the test scores for each group
Get a count of items in each group
Use that as a subquery and select only the middle 3 items (that's the where clause in the outer query)
Get the average for each group
--
select
group_id,
avg(test_value)
from (
select
t.group_id,
convert(decimal,t.test_value) as test_value,
row_number() over (
partition by t.group_id
order by t.test_value
) as ord,
g.gc
from
test t
inner join (
select group_id, count(*) as gc
from test
group by group_id
) g
on t.group_id = g.group_id
) a
where
ord >= case when gc <= 3 then 1 when gc % 2 = 1 then gc / 2 else (gc - 1) / 2 end
and ord <= case when gc <= 3 then 3 when gc % 2 = 1 then (gc / 2) + 2 else ((gc - 1) / 2) + 2 end
group by
group_id
with cte as (
select
*,
row_number() over(partition by group_id order by test_value) as rn,
count(*) over(partition by group_id) as cnt
from test
)
select
group_id, avg(test_value)
from cte
where
cnt <= 3 or
(rn >= cnt / 2 - 1 and rn <= cnt / 2 + 1)
group by group_id
order by group_id
sql fiddle demo
in the cte, we need to get count of elements over each group_id by window function + calculate row_number inside each group_id. Then, if this count > 3 then we need to get middle of the group by dividing count by 2 and then get +1 and -1 element. If count <= 3, then we should just take all elements.
This works:
SELECT A.group_id, avg(A.test_value) AS avg_mid3 FROM
(SELECT group_id,
test_value,
row_number() OVER (PARTITION BY group_id ORDER BY test_value) AS position
FROM test) A
JOIN
(SELECT group_id,
CASE
WHEN count(*) < 4 THEN 1
WHEN count(*) % 2 = 0 THEN (count(*)/2 - 1)
ELSE (count(*) / 2)
END AS position_start,
CASE
WHEN count(*) < 4 THEN count(*)
WHEN count(*) % 2 = 0 THEN (count(*)/2 + 1)
ELSE (count(*) / 2 + 2)
END AS position_end
FROM test GROUP BY group_id) B
ON A.group_id=B.group_id
AND A.position >= B.position_start
AND A.position <= B.position_end
GROUP BY A.group_id
Fiddle link: http://www.sqlfiddle.com/#!11/af5e0/56
If you need to calculate the average values for groups then you can do this:
SELECT CASE WHEN NUMBER_FIRST_GROUP <> 0
THEN SUM_FIRST_GROUP / NUMBER_FIRST_GROUP
ELSE NULL
END AS AVG_FIRST_GROUP,
CASE WHEN NUMBER_SECOND_GROUP <> 0
THEN SUM_SECOND_GROUP / NUMBER_SECOND_GROUP
ELSE NULL
END AS AVG_SECOND_GROUP,
CASE WHEN NUMBER_THIRD_GROUP <> 0
THEN SUM_THIRD_GROUP / NUMBER_THIRD_GROUP
ELSE NULL
END AS AVG_THIRD_GROUP,
CASE WHEN NUMBER_FOURTH_GROUP <> 0
THEN SUM_FOURTH_GROUP / NUMBER_FOURTH_GROUP
ELSE NULL
END AS AVG_FOURTH_GROUP
FROM (
SELECT
SUM(CASE WHEN GROUP_ID = 1 THEN 1 ELSE 0 END) AS NUMBER_FIRST_GROUP,
SUM(CASE WHEN GROUP_ID = 1 THEN TEST_VALUE ELSE 0 END) AS SUM_FIRST_GROUP,
SUM(CASE WHEN GROUP_ID = 2 THEN 1 ELSE 0 END) AS NUMBER_SECOND_GROUP,
SUM(CASE WHEN GROUP_ID = 2 THEN TEST_VALUE ELSE 0 END) AS SUM_SECOND_GROUP,
SUM(CASE WHEN GROUP_ID = 3 THEN 1 ELSE 0 END) AS NUMBER_THIRD_GROUP,
SUM(CASE WHEN GROUP_ID = 3 THEN TEST_VALUE ELSE 0 END) AS SUM_THIRD_GROUP,
SUM(CASE WHEN GROUP_ID = 4 THEN 1 ELSE 0 END) AS NUMBER_FOURTH_GROUP,
SUM(CASE WHEN GROUP_ID = 4 THEN TEST_VALUE ELSE 0 END) AS SUM_FOURTH_GROUP
FROM TEST
) AS FOO
I have a table like this :
Server CompliancePercentage
A 25
B 15
C 45
D 75
E 17
F 82
I want to get from a single query the results in the following way:
Conformity% 00-20 20-40 40-60 60-80 80-100
Server Count 2 1 1 1 1
How do I get the above mentioned result from a nested query ?
Any help would be greatful.
Thanks a lot in advance.
Suvi
You can use an aggregate function with a CASE expression to get the result:
select
'ServerCount' Conformity,
count(case when CompliancePercentage >= 0 and CompliancePercentage <20 then 1 end) Per00_19,
count(case when CompliancePercentage >= 20 and CompliancePercentage <40 then 1 end) Per20_39,
count(case when CompliancePercentage >= 40 and CompliancePercentage <60 then 1 end) Per40_59,
count(case when CompliancePercentage >= 60 and CompliancePercentage <80 then 1 end) Per60_79,
count(case when CompliancePercentage >= 80 and CompliancePercentage <100 then 1 end) Per80_100
from yourtable;
See SQL Fiddle with Demo
Assuming the following table:
create table dummyTable
(
srv char(1),
comp int
)
You can write out the query similar to
select
[00-19] = (SELECT COUNT(1) FROM dummyTable where comp between 0 and 19),
[20-39] = (SELECT COUNT(1) FROM dummyTable where comp between 20 and 39)
If your table has a ton of records (ie, > 1M) you may want to consider adding a non-clustered index to the table on the compliance percentage column to avoid a bunch of table scans.
Something like that should works for you:
SELECT
( COUNT(id) FROM table WHERE id > 1 ) AS id_gt_1,
( COUNT(id) FROM table WHERE id > 100 ) AS id_gt_100
Here, the criteria I have matched is simply the count for the ID number.
I have a table like this
C1 C2
1 0
1 1
i want the count of rows where c1=1 and the count of rows where c2=0 in one single query instead of separate queries.
select
sum(case c1 when 1 then 1 else 0 end) Count_c1,
sum(case c2 when 0 then 1 else 0 end) Count_c2
from YourTable
You can use the UNION keyword:
SELECT "ones", COUNT(*) WHERE c1=1
UNOIN
SELECT "zeroes", COUNT(*) WHERE c2=0