how i can GROUP BY entry_category if entry_category > 0
| entry_id | entry_title | entry_category |
-------------------------------
| 1 | xxx | 6 |
| 2 | xxx | 4 |
| 3 | xxx | 6 |
| 4 | xxx | 0 |
| 5 | xxx | 0 |
| 6 | xxx | 6 |
| 7 | xxx | 4 |
| 8 | xxx | 7 |
I want entrys category is set , not show duplicate :
| 1 | xxx | 6 |
| 2 | xxx | 4 |
| 4 | xxx | 0 |
| 5 | xxx | 0 |
| 8 | xxx | 7 |
Here is a way to do it, but there may be better way to do it. I took table name as test
select
entry_id,
entry_title,
entry_category
from
(
(
select
t1.entry_id,
t1.entry_title,
t1.entry_category
from test t1
left join test t2
on t1.entry_category = t2.entry_category
AND t1.entry_id < t2.entry_id
where t1.entry_category <> 0
group by t1.entry_category
)
union all
(
select entry_id,entry_title,entry_category from test
where entry_category = 0
)
)x
order by entry_id
DEMO
this is very good worked for me :
SELECT * FROM entrys
WHERE entry_category> 0
GROUP BY entry_category
UNION
SELECT * FROM entrys
WHERE entry_category= 0
good worked.
Related
I am designing a database for a web project in which I am trying to collect users' emotional feelings toward art collections. A hybrid dual list on the website allows users to select three options from 12 options and then rank the selected three as 1st, 2nd, and 3rd. There are 1000 data points in this project, which means there are 1000 distinct art collections for the users to vote on, each of the art collections has the same 12 options.
collection_poll
+-------+--------------------+
| id | collection_name |
+-------+--------------------+
| 1 | collection 1 |
| 2 | collection 2 |
| 3 | collection 3 |
| 4 | collection 4 |
| 5 | collection 5 |
| ... | ... |
+-------+--------------------+
option
+--------------------+--------------------+----------------+
| collection_id | option id | Text |
+--------------------+--------------------+----------------+
| 1 | 1 | Emotion 1 |
| 1 | 2 | Emotion 2 |
| 1 | 3 | Emotion 3 |
| 1 | 4 | Emotion 4 |
| 1 | 5 | Emotion 5 |
| 1 | 6 | Emotion 6 |
| 1 | 7 | Emotion 7 |
| 1 | 8 | Emotion 8 |
| 1 | 9 | Emotion 9 |
| 1 | 10 | Emotion 10 |
| 1 | 11 | Emotion 11 |
| 1 | 12 | Emotion 12 |
| 2 | 1 | Emotion 1 |
| 2 | 2 | Emotion 2 |
| 2 | 3 | Emotion 3 |
| 2 | 4 | Emotion 4 |
| 2 | 5 | Emotion 5 |
| ... | ... | ... |
+--------------------+--------------------+----------------|
vote
+--+-------+-------------+-------------+-------------+-------------+
|id|user_id|collection_id|1st_option_id|2nd_option_id|3rd_option_id|
+--+-------+-------------+-------------+-------------+-------------+
|1 | 1 | 1 | 1 | 8 | 12 |
|2 | 2 | 1 | 3 | 1 | 8 |
|3 | 3 | 1 | 1 | 8 | 3 |
|4 | 1 | 2 | 1 | 8 | 12 |
|5 | 2 | 2 | 3 | 12 | 8 |
|6 | 3 | 2 | 1 | 3 | 12 |
+--+-------+-------------+-------------+-------------+-------------+
This table records each vote and specifies which collection the user votes and the 1st, 2nd, and 3rd options the user ranks.
How do I use MySQL to get this table?
+---------------+-----------+-----------+-----------+-----------+
| collection_id | option_id | 1st_count | 2nd_count | 3rd_count |
+---------------+-----------+-----------+-----------+-----------+
| 1 | 1 | 2 | 1 | 0 |
| 1 | 2 | 0 | 0 | 0 |
| 1 | 3 | 1 | 0 | 1 |
| 1 | 4 | 0 | 0 | 0 |
| ... ... ... ... ... |
| 1 | 8 | 0 | 2 | 1 |
| ... ... ... ... ... |
| 1 | 12 | 0 | 0 | 1 |
| 2 | 1 | 2 | 0 | 0 |
| 2 | 2 | 0 | 0 | 0 |
| 2 | 3 | 1 | 1 | 0 |
| ... ... ... ... ... |
| 2 | 8 | 0 | 1 | 1 |
| ... ... ... ... ... |
| 2 | 12 | 0 | 1 | 2 |
| ... ... ... ... ... |
+---------------+-----------+-----------+-----------+-----------+
which uses collection_poll.id and option.id to get the result from table_vote.
I have
CREATE
OR REPLACE VIEW "public"."poll_results_first_option_count" AS
SELECT
vote.collection_id,
vote.first_option_id,
count(*) AS first_count
FROM
vote
GROUP BY
vote.collection_id,
vote.first_option_id
ORDER BY
vote.collection_id,
vote.first_option_id;
to get the count of each rank but cannot put them together.
The accepted answer does not provide the correct results. You need to be LEFT JOINing, starting from your option table and including option_id in the JOIN criteria:
SELECT `o`.`collection_id`, `o`.`option_id`,
`1st_count`,
`2nd_count`,
`3rd_count`
FROM `option` `o`
LEFT JOIN ( SELECT `collection_id`, `1st_option_id` AS `option_id`, COUNT(*) AS `1st_count` FROM `vote` GROUP BY 1, 2 ) AS `t1` USING (`collection_id`, `option_id`)
LEFT JOIN ( SELECT `collection_id`, `2nd_option_id` AS `option_id`, COUNT(*) AS `2nd_count` FROM `vote` GROUP BY 1, 2 ) AS `t2` USING (`collection_id`, `option_id`)
LEFT JOIN ( SELECT `collection_id`, `3rd_option_id` AS `option_id`, COUNT(*) AS `3rd_count` FROM `vote` GROUP BY 1, 2 ) AS `t3` USING (`collection_id`, `option_id`)
ORDER BY `o`.`collection_id`, `o`.`option_id`;
In your question you state:
each of the art collections has the same 12 options
If this is the case, then there is no need to link them in your option table. Instead you can just have the twelve options (and drop collection_id column) and CROSS JOIN to collection_poll to build the full list:
SELECT `cp`.`id`, `o`.`option_id`,
`1st_count`,
`2nd_count`,
`3rd_count`
FROM `collection_poll` `cp`
CROSS JOIN `option` `o`
LEFT JOIN ( SELECT `collection_id`, `1st_option_id` AS `option_id`, COUNT(*) AS `1st_count` FROM `vote` GROUP BY 1, 2 ) AS `t1` ON `cp`.`id` = `t1`.`collection_id` AND `o`.`option_id` = `t1`.`option_id`
LEFT JOIN ( SELECT `collection_id`, `2nd_option_id` AS `option_id`, COUNT(*) AS `2nd_count` FROM `vote` GROUP BY 1, 2 ) AS `t2` ON `cp`.`id` = `t2`.`collection_id` AND `o`.`option_id` = `t2`.`option_id`
LEFT JOIN ( SELECT `collection_id`, `3rd_option_id` AS `option_id`, COUNT(*) AS `3rd_count` FROM `vote` GROUP BY 1, 2 ) AS `t3` ON `cp`.`id` = `t3`.`collection_id` AND `o`.`option_id` = `t3`.`option_id`
ORDER BY cp.id, o.option_id;
Step 1: Do the sums
SELECT collection_id,
1st_option_id,
COUNT(*) AS 1st_count
FROM votes
GROUP BY 1,2
and do similarly for the others
Step 2: Put them together (somewhat like "pivot"):
SELECT collection_id,
1st_count,
2nd_count,
3rd_count
FROM ( ... ) AS t1
JOIN ( ... ) AS t2 USING(collection_id)
JOIN ( ... ) AS t3 USING(collection_id)
ORDER BY collection_id;
where the "..." comes from step 1
From the following game table of sports matches:
+-----+-----------+---------------+----------+-------+-------+---------+---------+
| id_ | date_time | tournament_id | round_id | p1_id | p2_id | p1_stat | p2_stat |
+-----+-----------+---------------+----------+-------+-------+---------+---------+
| 1 | NULL | 1 | 4 | 1 | 3 | 2 | 3 |
| 2 | NULL | 1 | 5 | 1 | 4 | 4 | 6 |
| 3 | NULL | 1 | 9 | 1 | 5 | 6 | 9 |
| 4 | NULL | 1 | 10 | 2 | 1 | 8 | 12 |
| 5 | NULL | 2 | 4 | 1 | 2 | 10 | 15 |
| 6 | NULL | 2 | 5 | 4 | 1 | 12 | 18 |
+-----+-----------+---------------+----------+-------+-------+---------+---------+
I'm trying to get the stats for each player for their previous match. The output should look like this:
+-----+--------------+--------------+
| id_ | prev_p1_stat | prev_p2_stat |
+-----+--------------+--------------+
| 1 | NULL | NULL |
| 2 | 2 | NULL |
| 3 | 4 | NULL |
| 4 | NULL | 6 |
| 5 | 12 | 8 |
| 6 | 6 | 10 |
+-----+--------------+--------------+
However, the date_time column is quite often blank and id_ is not date sequential. The tournament table does have a date_time column which is always populated:
+-----+------------+
| id_ | date_time |
+-----+------------+
| 1 | 1997-01-01 |
| 2 | 1997-01-06 |
+-----+------------+
This means the tournament date_time can be used in conjunction with game round_id to determine the previous match.
I've found the following answers here and here but they both focus on a single table and don't have the added complexity of having to determine whether the p1_stat or the p2_stat should be selected.
I've got as far as this query:
SELECT
g.id_ AS game_id,
CASE
WHEN g.p1_id = sq_p1.p1_id THEN sq_p1.p1_stat
ELSE sq_p1.p2_stat
END AS prev_p1_stat,
CASE
WHEN g.p1_id = sq_p2.p1_id THEN sq_p2.p1_stat
ELSE sq_p2.p2_stat
END AS prev_p2_stat
FROM
test.game AS g
JOIN
test.tournament AS t ON t.id_ = g.tournament_id
LEFT OUTER JOIN
(SELECT
g.id_ AS match_id,
t.date_time AS tournament_date,
g.round_id,
g.p1_id,
g.p2_id,
g.p1_stat,
g.p2_stat
FROM
test.game AS g
JOIN test.tournament AS t ON t.id_ = g.tournament_id) AS sq_p1 ON (sq_p1.p1_id = g.p1_id
OR sq_p1.p2_id = g.p1_id)
AND (sq_p1.tournament_date = t.date_time
AND sq_p1.round_id < g.round_id
OR sq_p1.tournament_date < t.date_time)
LEFT OUTER JOIN
(SELECT
g.id_ AS match_id,
t.date_time AS tournament_date,
g.round_id,
g.p1_id,
g.p2_id,
g.p1_stat,
g.p2_stat
FROM
test.game AS g
JOIN test.tournament AS t ON t.id_ = g.tournament_id) AS sq_p2 ON (sq_p2.p1_id = g.p1_id
OR sq_p2.p2_id = g.p1_id)
AND (sq_p2.tournament_date = t.date_time
AND sq_p2.round_id < g.round_id
OR sq_p2.tournament_date < t.date_time)
ORDER BY t.date_time , g.round_id
But this isn't even close to what I'm looking for :(
I've created a dbfiddle.
One other thing that's perhaps worth mentioning... I intend to use a couple of versions of this query in a union query such that the final result (including all columns for reference) will look like this:
+-----+------------+-----------+-------------+-------------+---------------+------------------+--------------------+
| id_ | player_num | player_id | opponent_id | player_stat | opponent_stat | player_prev_stat | opponent_prev_stat |
+-----+------------+-----------+-------------+-------------+---------------+------------------+--------------------+
| 1 | 1 | 1 | 3 | 2 | 3 | NULL | NULL |
| 1 | 2 | 3 | 1 | 3 | 2 | NULL | NULL |
| 2 | 1 | 1 | 4 | 4 | 6 | 2 | NULL |
| 2 | 2 | 4 | 1 | 6 | 4 | NULL | 2 |
| 3 | 1 | 1 | 5 | 6 | 9 | 4 | NULL |
| 3 | 2 | 5 | 1 | 9 | 6 | NULL | 4 |
| 4 | 1 | 2 | 1 | 8 | 12 | NULL | 6 |
| 4 | 2 | 1 | 2 | 12 | 8 | 6 | NULL |
| 5 | 1 | 1 | 2 | 10 | 15 | 12 | 8 |
| 5 | 2 | 2 | 1 | 15 | 10 | 8 | 12 |
| 6 | 1 | 4 | 1 | 12 | 18 | 6 | 10 |
| 6 | 2 | 1 | 4 | 18 | 12 | 10 | 6 |
+-----+------------+-----------+-------------+-------------+---------------+------------------+--------------------+
Perhaps it makes more sense to do a union and then engineer the previous stats?
For some final info, the actual game table has about 1.5m rows and the actual tournament table has about 30k rows. I'm using MySQL 8.0.26.
Kudos to #Barmer for the direction - here's the query I created using LAG():
WITH union_matches AS (
SELECT
g.id_ AS match_id,
t.date_time AS tournament_date,
g.round_id AS round_id,
1 AS player_num,
g.p1_id AS player_id,
g.p2_id AS opponent_id,
g.p1_stat AS player_stat,
g.p2_stat AS opponent_stat
FROM
game AS g
JOIN
tournament AS t ON t.id_ = g.tournament_id
UNION SELECT
g.id_ AS match_id,
t.date_time AS tournament_date,
g.round_id AS round_id,
2 AS player_num,
g.p2_id AS player_id,
g.p1_id AS opponent_id,
g.p2_stat AS player_stat,
g.p1_stat AS opponent_stat
FROM
game AS g
JOIN
tournament AS t ON t.id_ = g.tournament_id
)
SELECT
match_id,
player_num,
player_id,
opponent_id,
player_stat,
opponent_stat,
LAG(player_stat, 1) OVER (PARTITION BY player_id ORDER BY tournament_date, round_id) AS wrong_player_prev_stat,
LAG(opponent_stat, 1) OVER (PARTITION BY opponent_id ORDER BY tournament_date, round_id) AS wrong_opponent_prev_stat
FROM
union_matches
ORDER BY
tournament_date, round_id, player_num
And a link to the dbfiddle.
I have a user - course - exam database.
Table structures:
user table structure
+--------------------------------------------+
| user |
+--------------------------------------------+
| user_id | fullname | email |
+---------+--------------+-------------------+
| 1 | Test User 01 | test01#domain.com |
+---------+--------------+-------------------+
| 2 | Test User 02 | test02#domain.com |
+---------+--------------+-------------------+
| 3 | Test User 03 | test03#domain.com |
+---------+--------------+-------------------+
| 4 | Test User 04 | test04#domain.com |
+---------+--------------+-------------------+
course table structure
+-----------------------+
| course |
+-----------------------+
| course_id | title |
+-----------+-----------+
| 1 | Course 01 |
+-----------+-----------+
| 2 | Course 02 |
+-----------+-----------+
| 3 | Course 03 |
+-----------+-----------+
course_exam table structure (course can have one or more exam)
+----------------------------+
| course_exam |
+----------------------------+
| course_exam_id | course_id |
+----------------+-----------+
| 1 | 1 |
+----------------+-----------+
| 2 | 1 |
+----------------+-----------+
| 3 | 2 |
+----------------+-----------+
| 4 | 3 |
+----------------+-----------+
| 5 | 2 |
+----------------+-----------+
user_course_exam table structure (users can join one or more exam)
+---------------------------------------------------------------------------------------------------------------+
| user_course_exam |
+---------------------------------------------------------------------------------------------------------------+
| user_course_exam_id | course_exam_id | user_id | right_answer_total | wrong_answer_total | blank_answer_total |
+---------------------+----------------+---------+--------------------+--------------------+--------------------+
| 1 | 1 | 1 | 2 | 3 | 0 |
+---------------------+----------------+---------+--------------------+--------------------+--------------------+
| 2 | 1 | 1 | 4 | 1 | 0 |
+---------------------+----------------+---------+--------------------+--------------------+--------------------+
| 3 | 2 | 1 | 5 | 0 | 0 |
+---------------------+----------------+---------+--------------------+--------------------+--------------------+
| 4 | 1 | 1 | 3 | 1 | 1 |
+---------------------+----------------+---------+--------------------+--------------------+--------------------+
| 5 | 3 | 1 | 4 | 0 | 1 |
+---------------------+----------------+---------+--------------------+--------------------+--------------------+
I should prepare a report like below:
user_id
fullname
email
completed_course_total (course total having completed exams by user)
remaining_course_total
right_answer_total (Max right answer for best scored exam. Only one result should fetch for each course)
Expected report result
+-------------------------------------------------------------------------------------------------------------------+
| user_id | fullname | email | completed_course_total | remaining_course_total | right_answer_total |
+---------+--------------+-------------------+------------------------+------------------------+--------------------+
| 1 | Test User 01 | test01#domain.com | 2 | 1 | 13 |
+---------+--------------+-------------------+------------------------+------------------------+--------------------+
| 2 | Test User 02 | test02#domain.com | 0 | 3 | 0 |
+---------+--------------+-------------------+------------------------+------------------------+--------------------+
| 3 | Test User 03 | test03#domain.com | 0 | 3 | 0 |
+---------+--------------+-------------------+------------------------+------------------------+--------------------+
| 4 | Test User 04 | test04#domain.com | 0 | 3 | 0 |
+---------+--------------+-------------------+------------------------+------------------------+--------------------+
This is my query, but right answer result returns all of exams. I want get only sum of max right answer total for each courses.
Please also consider these cases:
A course can have more than one exams.
A user can join more than one course_exam.
SELECT DISTINCT
`user`.user_id,
(
SELECT COUNT(DISTINCT(`user_course_exam`.`course_exam_id`)) FROM `user_course_exam`
INNER JOIN `course_exam` ON (`course_exam`.`course_exam_id` = `user_course_exam`.`course_exam_id`)
WHERE `user_course_exam`.`user_id` = `user`.`user_id` && `course_exam`.course_id IN (
SELECT course_id FROM course_exam
WHERE status = '1'
GROUP BY `course_exam`.`course_id`
)
) AS completed_course,
(
SELECT SUM(`user_course_exam`.`right_answer_total`) FROM `user_course_exam`
INNER JOIN `course_exam` ON (`course_exam`.`course_exam_id` = `user_course_exam`.`course_exam_id`)
WHERE `user_course_exam`.`user_id` = `user`.`user_id` && `course_exam`.course_id IN (
SELECT course_id FROM course_exam
WHERE status = '1'
GROUP BY `course_exam`.`course_id`
) ORDER BY `user_course_exam`.`right_answer_total` DESC
) AS right_answer
FROM
`user`
WHERE
`user`.`user_id` > 0
GROUP BY
`user`.`user_id`
ORDER BY
`user`.`user_id` ASC
LIMIT 15 OFFSET 0
JSFiddle: http://sqlfiddle.com/#!9/72ee15/1/0
You can try to use MAX() than SUM()
SELECT DISTINCT `user`.`user_id`,
(
SELECT COUNT(DISTINCT (`user_course_exam`.`course_exam_id`))
FROM `user_course_exam`
INNER JOIN `course_exam`
ON (`course_exam`.`course_exam_id` = `user_course_exam`.`course_exam_id`)
WHERE `user_course_exam`.`user_id` = `user`.`user_id` && `course_exam`.`course_id` IN (
SELECT `course_id`
FROM `course_exam`
GROUP BY `course_exam`.`course_id`
)
) AS `completed_course`,
(
SELECT sum(`all_curse`.`max_right_answer`)
FROM (
SELECT MAX(`user_course_exam`.`right_answer_total`) AS `max_right_answer`,
`user_course_exam`.`user_id`
FROM `user_course_exam`
INNER JOIN `course_exam`
ON `course_exam`.`course_exam_id` = `user_course_exam`.`course_exam_id`
WHERE `course_exam`.`status` = 1
GROUP BY `course_exam`.`course_id`, `course_exam`.`course_exam_id`
) AS `all_curse`
WHERE `all_curse`.`user_id` = `user`.`user_id`
) AS `right_answer`
FROM `user`
WHERE `user`.`user_id` > 0
GROUP BY `user`.`user_id`
ORDER BY `user`.`user_id`
LIMIT 15 OFFSET 0
JSFiddle: Here
I have table as below , I want to take latest rating for the client
basically user whenever updates rating, count will be incremented and a entry will be made in table. Table goes as below
-----------------------------------------------------
|_id| name | client_id | user_id | rating | count |
-----------------------------------------------------
|1 | Four | 1 | 1 | 4 | 1 |
|2 | three | 1 | 1 | 3 | 2 |
|3 | two | 1 | 1 | 2 | 3 |
|4 | five | 1 | 1 | 5 | 4 |
|5 | two | 1 | 2 | 2 | 1 |
|6 | three | 1 | 2 | 3 | 2 |
|7 | two | 2 | 1 | 2 | 1 |
|8 | three | 2 | 1 | 3 | 2 |
-----------------------------------------------------
For rating of client_id 1 I want out put like
-----------------------------------------------------
|_id| name | client_id | user_id | rating | count |
-----------------------------------------------------
|4 | five | 1 | 1 | 5 | 4 |
|6 | three | 1 | 2 | 3 | 2 |
-----------------------------------------------------
so far I tried SELECT * FROM test
where client_id = 1 group by client_id order by count desc;
but not getting expected result, any help??
You can use left join on the same table as
select t1.* from test t1
left join test t2 on t1.user_id = t2.user_id
and t1.client_id = t2.client_id
and t1._id < t2._id
where
t2._id is null
and t1.client_id = 1
order by t1.`count` desc;
Using un-correlated subquery you may do as
select t1.* from test t1
join (
select max(_id) as _id,
client_id,
user_id
from test
where client_id = 1
group by client_id,user_id
)t2
on t1._id = t2._id
and t1.client_id = t2.client_id
order by t1.`count` desc;
UPDATE : From the comment how to join another table into above , for this here is an example
mysql> select * from users ;
+------+------+
| _id | name |
+------+------+
| 1 | AAA |
| 2 | BBB |
+------+------+
2 rows in set (0.00 sec)
mysql> select * from test ;
+------+-------+-----------+---------+--------+-------+
| _id | name | client_id | user_id | rating | count |
+------+-------+-----------+---------+--------+-------+
| 1 | four | 1 | 1 | 4 | 1 |
| 2 | three | 1 | 1 | 3 | 2 |
| 3 | two | 1 | 1 | 2 | 3 |
| 4 | five | 1 | 1 | 5 | 4 |
| 5 | two | 1 | 2 | 2 | 1 |
| 6 | three | 1 | 2 | 3 | 2 |
| 7 | two | 2 | 1 | 2 | 1 |
| 8 | three | 2 | 1 | 3 | 2 |
+------+-------+-----------+---------+--------+-------+
select t1.*,u.name from test t1
join users u on u._id = t1.user_id
left join test t2 on t1.user_id = t2.user_id
and t1.client_id = t2.client_id
and t1._id < t2._id
where
t2._id is null
and t1.client_id = 1
order by t1.`count` desc;
Will give you
+------+-------+-----------+---------+--------+-------+------+
| _id | name | client_id | user_id | rating | count | name |
+------+-------+-----------+---------+--------+-------+------+
| 4 | five | 1 | 1 | 5 | 4 | AAA |
| 6 | three | 1 | 2 | 3 | 2 | BBB |
+------+-------+-----------+---------+--------+-------+------+
Note that the join to users table is inner join and this will require all the user to be preset in users table which are in test table
If some users are missing in the users table then use left join this will have null values for the data selected from users table.
You may try something like
select _id, name, client_id, user_id, rating, max(count)
from clients
group by client_id
Try it
SELECT * FROM test
where client_id = 1
group by user_id
order by count desc
I have a query and a result as follows.
In the database NULL and 0 represent the same meaning.
Now I want a counter based on Null+0 or 1
Eg:in the following example I want the result like this:
IsVirtual Category counter
NULL+0 3 343+8 = (351 is Total)
Query
select * from
(
Select IsVirtual, Category, count(*) as counter
from [Hardware]
group by IsVirtual, Category
) innercat
Output
+-----------+----------+---------+
| IsVirtual | Category | counter |
+-----------+----------+---------+
| NULL | 3 | 343 |
| 0 | 3 | 8 |
| 1 | 2 | 1 |
| 0 | 1 | 1 |
| NULL | 6 | 119 |
| 0 | 4 | 1 |
| NULL | 1 | 70 |
| 0 | 5 | 9 |
| NULL | 4 | 54 |
| 0 | 2 | 2 |
| NULL | 5 | 41 |
| NULL | 2 | 112 |
| 1 | 1 | 5 |
+-----------+----------+---------+
I think you want this :
SELECT COALESCE(IsVirtual, 0) as [IsVirtual],
Category,
Count(*) as [Counter]
FROM yourtable
GROUP BY COALESCE(IsVirtual, 0),Category
This will give you expected result without using subquery.
try with this
select * from (
Select CASE ISNULL(IsVirtual,0)
WHEN 0 Then 'NULL + 0'
ELSE IsVirtual
END AS IsVirtual, Category, count(*) as counter from [Hardware] group by ISNULL(IsVirtual,0), Category
)innercat
You can also do the same thing by using MAX function
This might help you.
SELECT
max(IsVirtual) as IsVirtual,
Category,
Count(*) as Counter
FROM
yourtable
GROUP BY
Category