I Have a SQL Table as shown below,
| Loc | Date | Id | Sts |
-------------------------
| Hyd | 15-01-2016 | 1 | A |
| Vjd | 16-01-2016 | 2 | B |
| Viz | 15-01-2016 | 3 | C |
| Hyd | 15-03-2016 | 4 | A |
| Vjd | 15-03-2016 | 5 | B |
| Viz | 15-03-2016 | 6 | C |
| Hyd | 15-03-2016 | 4 | A |
| Vjd | 15-05-2016 | 5 | B |
| Viz | 15-05-2016 | 6 | C |
And i need output like,
**| Loc | Jan-16 | Mar-16 | May-16 |**
**|-------|A |B |C |A |B |C |A |B |C |**
----------
|Hyd | 1 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 |
|Vjd | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
|Viz | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 |
Can anyone help me out please..
Thanks in Advance.
You will basically need to aggregate based on CASE statements, like this:
DECLARE #table TABLE (loc VARCHAR(3), [date] DATE, id INT, sts CHAR(1));
INSERT INTO #table SELECT 'Hyd', '20160115', 1, 'A';
INSERT INTO #table SELECT 'Vjd', '20160116', 2, 'B';
INSERT INTO #table SELECT 'Viz', '20160115', 3, 'C';
INSERT INTO #table SELECT 'Hyd', '20160315', 4, 'A';
INSERT INTO #table SELECT 'Vjd', '20160315', 5, 'B';
INSERT INTO #table SELECT 'Viz', '20160315', 6, 'C';
INSERT INTO #table SELECT 'Hyd', '20160315', 4, 'A';
INSERT INTO #table SELECT 'Vjd', '20160515', 5, 'B';
INSERT INTO #table SELECT 'Viz', '20160515', 6, 'C';
SELECT
loc,
COUNT(CASE WHEN YEAR([date]) = 2016 AND MONTH([date]) = 1 AND sts = 'A' THEN 1 END) AS Jan_A,
COUNT(CASE WHEN YEAR([date]) = 2016 AND MONTH([date]) = 1 AND sts = 'B' THEN 1 END) AS Jan_B,
COUNT(CASE WHEN YEAR([date]) = 2016 AND MONTH([date]) = 1 AND sts = 'C' THEN 1 END) AS Jan_C,
COUNT(CASE WHEN YEAR([date]) = 2016 AND MONTH([date]) = 3 AND sts = 'A' THEN 1 END) AS Mar_A,
COUNT(CASE WHEN YEAR([date]) = 2016 AND MONTH([date]) = 3 AND sts = 'B' THEN 1 END) AS Mar_B,
COUNT(CASE WHEN YEAR([date]) = 2016 AND MONTH([date]) = 3 AND sts = 'C' THEN 1 END) AS Mar_C,
COUNT(CASE WHEN YEAR([date]) = 2016 AND MONTH([date]) = 5 AND sts = 'A' THEN 1 END) AS May_A,
COUNT(CASE WHEN YEAR([date]) = 2016 AND MONTH([date]) = 5 AND sts = 'B' THEN 1 END) AS May_B,
COUNT(CASE WHEN YEAR([date]) = 2016 AND MONTH([date]) = 5 AND sts = 'C' THEN 1 END) AS May_C
FROM
#table
GROUP BY
loc;
Results:
loc Jan_A Jan_B Jan_C Mar_A Mar_B Mar_C May_A May_B May_C
Hyd 1 0 0 2 0 0 0 0 0
Viz 0 0 1 0 0 1 0 0 1
Vjd 0 1 0 0 1 0 0 1 0
Related
Consider the following 2 tables.
TableDE
ID country key1 key2
------------------------
1 US 1 null
1 US 1 null
1 US 1 null
2 US null null
3 US 1 1
4 DE 1 1
5 DE null null
5 DE null null
TableUS
ID key1 key2
--------------
1 null null
2 null 1
4 1 1
8 null 1
2 null 1
2 null 1
9 1 null
I need a distinct overview of all IDs, combining data from both tables:
ID inTableDe country DEkey1 DEkey2 inTableUS USkey1 USKey2
-----------------------------------------------------------------
1 1 US 1 0 1 0 0
2 1 US 0 0 1 0 1
3 1 US 1 1 0 0 0
4 1 DE 1 1 1 1 1
5 1 DE 0 0 0 0 0
8 0 0 0 1 1 0 1
9 0 0 0 1 1 1 0
I hope it speaks for itself:
ID 8 and ID 9 have 0 in the first column bc they aren't in tableDE
ID 8 and ID 9 have 0 in the country column bc this field doesn't exist in tableUS
ID 3 has 0 in inTableUS bc it only exists in tableDE
the key values are copied from the original tables
an ID is not unique: it can appear many times in both tables. However: the values for key1 and key2 will always be the same for each ID within the same table.
I have been messing for hours now with this; I have this now:
select de.[ID],
de.[country],
case when (de.[ID] in (select distinct [ID] from [tableDE]) then 1 else 0 end as [inTableDE],
case when (de.[ID] in (select distinct [ID] from [tableUS]) then 1 else 0 end as [inTableUS],
de.[key1] as [DEKey1],
de.[key2] as [DEKey2],
us.[key1] as [USKey1],
us.[key2] as [USKey2],
from dbo.[tableDE] de
full outer join dbo.[tableUS] us on de.[ID] = us.[ID]
where de.[country] = 'US'
and (de.[key1] = 1 or de.[key2] = 1 or us.[key1] = 1 or us.[key2] = 1)
group by de.[ID], us.[ID]
But this keeps giving me only values that are in both tables.
What am I doing wrong?
You sem to want aggregation on top of the full join:
select
coalesce(de.id, us.id) as id,
case when de.id is null then 0 else 1 end as intablede,
max(de.country) as country,
coalesce(max(de.key1), 0) as dekey1,
coalesce(max(de.key2), 0) as dekey2,
case when us.id is null then 0 else 1 end as intableus,
coalesce(max(us.key1), 0) as uskey1,
coalesce(max(us.key2), 0) as uskey2
from dbo.tablede de
full join dbo.tableus us on de.id = us.id
group by de.id, us.id
order by id
Demo on DB Fiddle:
id | intablede | country | dekey1 | dekey2 | intableus | uskey1 | uskey2
-: | --------: | :------ | -----: | -----: | --------: | -----: | -----:
1 | 1 | US | 1 | 0 | 1 | 0 | 0
2 | 1 | US | 0 | 0 | 1 | 0 | 1
3 | 1 | US | 1 | 1 | 0 | 0 | 0
4 | 1 | DE | 1 | 1 | 1 | 1 | 1
5 | 1 | DE | 0 | 0 | 0 | 0 | 0
8 | 0 | null | 0 | 0 | 1 | 0 | 1
9 | 0 | null | 0 | 0 | 1 | 1 | 0
I have a table "tbTest1" like this:
q1 | q2 | q3 | type
---+----+----+-----------
3 | 2 | 2 | Student
2 | 2 | 3 | Student
3 | 1 | 1 | Alumni
1 | 1 | 3 | Student
1 | 3 | 2 | Alumni
Now I want to convert "tbTest1" into like this where how many 1's,2's or 3's had given by Student for 'q1', 'q2' & 'q3' :
q | 1 | 2 | 3
---+---+---+---
q1 | 1 | 1 | 1
q2 | 1 | 2 | 0
q3 | 0 | 1 | 2
You can use conditional aggregation:
select v.q,
sum(case when val = 1 then 1 else 0 end) as val_1,
sum(case when val = 2 then 1 else 0 end) as val_2,
sum(case when val = 3 then 1 else 0 end) as val_3
from tbTest t cross apply
(values ('q1', t.q1), ('q2', t.q2), ('q3', t.q3)) v(q, val)
where t.type = 'student'
group by v.q;
I am working on some survey data and was wondering if i could rearrange the data to make it a lot more usable. The results are classified as 1-5 and I would like the preferred table to count the results by value and group by question.
original table:
year | month | customer_id | survey | q1 | q2 | q3 | q4 | q5 | q6 ----> q29
-----|-------|-------------|--------|----|----|----|----|----|---
2016 | Oct | ABC12345678 | 1 | 1 | 2 | 3 | 1 | 2 | 3
2016 | Oct | DEF12345678 | 1 | 2 | 1 | 4 | 2 | 1 | 1
2016 | Oct | GHI12345678 | 1 | 4 | 2 | 1 | 1 | 3 | 2
2016 | Oct | JKL12345678 | 1 | 2 | 3 | 2 | 4 | 1 | 3
2016 | Oct | MNO12345678 | 1 | 5 | 2 | 3 | 1 | 2 | 3
2016 | Oct | PQR12345678 | 1 | 3 | 4 | 4 | 2 | 4 | 4
2016 | Oct | STU12345678 | 1 | 1 | 5 | 3 | 1 | 2 | 5
2016 | Oct | VWX12345678 | 1 | 2 | 2 | 4 | 2 | 1 | 1
Preferred Table:
Year | Month | Survey | Question | 1 | 2 | 3 | 4 | 5 |
-----|-------|--------|----------|----|----|----|----|----|
2016 | Oct | 1 | q1 | 80 | 45 | 25 | 63 | 89 |
2016 | Oct | 1 | q2 | 65 | 75 | 35 | 53 | 69 |
I can do this with a basic select query but to do it for every question will end up with 29 unions and there must be a quicker way.
Regards,
Neil
This is what I would use until someone posts a better solution:
<!-- language: lang-sql -->
use tempdb;
create table #tempsurvey (year int, month varchar(32), customer_id varchar(32), survey int, [q1] int, [q2] int, [q3] int, [q4] int, [q5] int, [q6] int, [q7] int, [q8] int, [q9] int, [q10] int, [q11] int, [q12] int, [q13] int, [q14] int, [q15] int, [q16] int, [q17] int, [q18] int, [q19] int, [q20] int, [q21] int, [q22] int, [q23] int, [q24] int, [q25] int, [q26] int, [q27] int, [q28] int, [q29] int);
insert into #tempsurvey values (2016,'Oct', 'ABC12345678', 1, 1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2);
insert into #tempsurvey values (2016,'Oct', 'DEF12345678', 1, 4,5,1,4,5,1,4,5,1,4,5,1,4,5,1,4,5,1,4,5,1,4,5,1,4,5,1,4,5);
with cte as (
select t.[year], t.[month], t.customer_id, t.survey, x.question, x.answer
from #tempsurvey t
cross apply (values ('q1',q1) ,('q2',q2) ,('q3',q3) ,('q4',q4) ,('q5',q5) ,('q6',q6) ,('q7',q7) ,('q8',q8) ,('q9',q9) ,('q10',q10) ,('q11',q11) ,('q12',q12) ,('q13',q13) ,('q14',q14) ,('q15',q15) ,('q16',q16) ,('q17',q17) ,('q18',q18) ,('q19',q19) ,('q20',q20) ,('q21',q21) ,('q22',q22) ,('q23',q23) ,('q24',q24) ,('q25',q25) ,('q26',q26) ,('q27',q27) ,('q28',q28) ,('q29',q29))
as x (Question,Answer)
)
select [year], [month], [survey], question, [1]=sum(case when answer=1 then 1 else 0 end), [2]=sum(case when answer=2 then 1 else 0 end), [3]=sum(case when answer=3 then 1 else 0 end), [4]=sum(case when answer=4 then 1 else 0 end), [5]=sum(case when answer=5 then 1 else 0 end)
from cte
group by [year], [month], [survey], question;
drop table #tempsurvey;
Brad Schulz on cross apply: http://bradsruminations.blogspot.com/search/label/CROSS%20APPLY
Sean is correct.
It will go like this:
with subquery as (
select year, month, survey, question, tempVal from #table
unpivot
(tempVal for question in (q1, q2, q3, q4, q5, q6, q7, ..., q29)) as up
)
select year, month, survey, question,
sum(case when tempVal = 1 then 1 else 0 end) as a1,
sum(case when tempVal = 2 then 1 else 0 end) as a2,
sum(case when tempVal = 3 then 1 else 0 end) as a3,
sum(case when tempVal = 4 then 1 else 0 end) as a4,
sum(case when tempVal = 5 then 1 else 0 end) as a5
from subquery
group by year, month, survey, question
I have a query (which works) however, I want to be able to make it so I don't need to rerun the query to change the date ranges.
What I have here is it is pulling customer name and the amount and summing it. I need it broken down monthly by fiscal year, so what I would just do is change the year and rerun it, but I want to make the query more efficient so it doesn't need to be changed in the future (except the end date for a new FY) So after it takes the sum of each month (July to June), I want it to show the FY. So the date ranges from 2014 to 2015 should show a column called FY and have 2015 in the column. I am pretty certain I am on the right track but not there. I only showed what I was working on for the first case (which will be replicated for the other cases)
Could this just be an IF statement loop instead of another case statement? Any help with direction would be great to help me learn. I got this far, but just want to make the code more efficient for someone to use
Declare #StartDate datetime
Declare #EndDate datetime
set #StartDate = convert(datetime, '07/01/2014')
set #EndDate = convert(datetime, '06/30/2017')
select
d.CUSTNMBR Customer_ID,
d.CUSTNAME Customer_Name,
'A' as Company,
sum(case when month(d.DOCDATE) = 7
then d.SALES else 0 end) July,
case when datetime between '07/01/2016' and '06/30/2017' as '2017'
when datetime between '07/01/2015' and '06/30/2016' as '2016'
when datetime between '07/01/2014' and '06/30/2015' as '2015'
END
sum(case when month(d.DOCDATE) = 8
then d.SALES else 0 end) August,
sum(case when month(d.DOCDATE) = 9
then d.SALES else 0 end) September,
sum(case when month(d.DOCDATE) = 10
then d.SALES else 0 end) October,
sum(case when month(d.DOCDATE) = 11
then d.SALES else 0 end) November,
sum(case when month(d.DOCDATE) = 12
then d.SALES else 0 end) December,
sum(case when month(d.DOCDATE) = 1
then d.SALES else 0 end) January,
sum(case when month(d.DOCDATE) = 2
then d.SALES else 0 end) February,
sum(case when month(d.DOCDATE) = 3
then d.SALES else 0 end) March,
sum(case when month(d.DOCDATE) = 4
then d.SALES else 0 end) April,
sum(case when month(d.DOCDATE) = 5
then d.SALES else 0 end) May,
sum(case when month(d.DOCDATE) = 6
then d.SALES else 0 end) June,
sum(d.SALES) 'Year to Date'
from
(select s.DOCDATE, s.CUSTNMBR, c.CUSTNAME,
case s.SOPTYPE
when 3 then s.DOCAMNT
when 4 then s.DOCAMNT*-1
end SALES
from a1.dbo.S200 s
left outer join a1.dbo.RM1 c
on s.CUSTNMBR = c.CUSTNMBR
where s.VOIDSTTS = 0
and s.SOPTYPE in (3,4) and
s.DOCDATE between #StartDate and #EndDate -- Fiscal Year
) d
group by d.CUSTNMBR, d.CUSTNAME
Consider a recursive CTE that iterates through each fiscal year and then run a CROSS JOIN...WHERE (CROSS APPLY can work too) on your existing derived table. The WHERE conditions DOCDate to fiscal year start and end ranges. And going forward, simply change the declaration lines for each fiscal year. In fact, you can set up #end INT = 2020 to anticipate future data!
DECLARE #start INT = 2014;
DECLARE #end INT = 2016;
WITH fiscalyears AS (
SELECT #start + 1 AS FY,
CONVERT(datetime, cast(1 as varchar)+'/'+cast(7 as varchar)+'/'+cast(#start as varchar), 103) As StartRng,
CONVERT(datetime, cast(30 as varchar)+'/'+cast(6 as varchar)+'/'+cast(#start + 1 as varchar), 103) As EndRng
UNION ALL
SELECT FY + 1,
CONVERT(datetime, cast(1 as varchar)+'/'+cast(7 as varchar)+'/'+cast(FY + 1 as varchar), 103),
CONVERT(datetime, cast(30 as varchar)+'/'+cast(6 as varchar)+'/'+cast(FY + 2 as varchar), 103)
FROM fiscalyears
WHERE FY < #end
)
-- FY StartRng EndRng
-- 2015 2014-07-01 00:00:00.000 2015-06-30 00:00:00.000
-- 2016 2015-07-01 00:00:00.000 2016-06-30 00:00:00.000
---2017 2016-07-01 00:00:00.000 2017-06-30 00:00:00.000
select
d.CUSTNMBR Customer_ID,
d.CUSTNAME Customer_Name,
'A' as Company,
d.FY As FY,
sum(case when month(d.DOCDATE) = 7 then d.SALES else 0 end) AS July,
sum(case when month(d.DOCDATE) = 8 then d.SALES else 0 end) AS August,
sum(case when month(d.DOCDATE) = 9 then d.SALES else 0 end) AS September,
sum(case when month(d.DOCDATE) = 10 then d.SALES else 0 end) AS October,
sum(case when month(d.DOCDATE) = 11 then d.SALES else 0 end) AS November,
sum(case when month(d.DOCDATE) = 12 then d.SALES else 0 end) AS December,
sum(case when month(d.DOCDATE) = 1 then d.SALES else 0 end) AS January,
sum(case when month(d.DOCDATE) = 2 then d.SALES else 0 end) AS February,
sum(case when month(d.DOCDATE) = 3 then d.SALES else 0 end) AS March,
sum(case when month(d.DOCDATE) = 4 then d.SALES else 0 end) AS April,
sum(case when month(d.DOCDATE) = 5 then d.SALES else 0 end) AS May,
sum(case when month(d.DOCDATE) = 6 then d.SALES else 0 end) AS June,
sum(d.SALES) 'Year to Date'
from
(select f.FY, s.DOCDATE, s.CUSTNMBR, c.CUSTNAME,
case s.SOPTYPE
when 3 then s.DOCAMNT
when 4 then s.DOCAMNT*-1
end SALES
from a1.dbo.S200 s
left outer join a1.dbo.RM1 c
on s.CUSTNMBR = c.CUSTNMBR
cross join fiscalyears f
where s.VOIDSTTS = 0
and s.SOPTYPE in (3,4)
and s.DOCDATE between f.StartRng and f.EndRng) d
group by d.CUSTNMBR,
d.CUSTNAME,
d.FY
Do you have access to create functions? If so, create a (re-usable) scalar function for FY. E.g.:
CREATE FUNCTION dbo.FY (input_date as smalldatetime)
RETURNS int
BEGIN
DECLARE #return int
SET #return = year(input_date)
IF month(input_date) <= 6
#return = #return + 1
RETURN #return
END
Then Use the function in your SELECT...
SELECT
...,
FY(d.DOCDATE),
...
FROM
...
Otherwise, you can inline the function -- e.g.:
SELECT
...,
CASE WHEN Month(d.DOCDATE) <= 6 THEN 1 ELSE 0 END + year(d.DOCDATE) as FY
...
Also worth mentioning -- it looks like you're naming your Months the hard way.
Try this instead:
DATENAME(month,d.DOCDATE),
Also...
Suggest keeping your query's data and layout separated a bit more (for example, where you're create a horizontal layout for your months) -- you might like what PIVOT (https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx) can do for you...
If you do this, you can keep your query's data a little cleaner -- and then use it's output in other queries as well. More re-usability = less work for you! :-)
I am proposing that the S200 table shall have computed columns as helper like this:
create table S200
(
CUSTNMBR varchar(10) null,
DOCDATE date null,
SOPTYPE int null,
DOCAMNT money null,
FISCALYEAR as datepart(year, DOCDATE) +
case when datepart(month, DOCDATE) >= 7 then 1 else 0 end,
FISCALMONTHNAME as (datename(month, DOCDATE))
)
Then we can simply PIVOT it like:
select
*,
isnull([January], 0) +
isnull([February], 0) +
isnull([March], 0) +
isnull([April], 0) +
isnull([May], 0) +
isnull([June], 0) +
isnull([July], 0) +
isnull([August], 0) +
isnull([September], 0) +
isnull([October], 0) +
isnull([November], 0) +
isnull([December], 0) as YearToDate
from
(
select
s.CUSTNMBR,
s.FISCALYEAR,
FISCALMONTHNAME,
case s.SOPTYPE
when 3 then s.DOCAMNT
when 4 then -s.DOCAMNT
end as SALES
from
S200 as s
)
as d
pivot
(
sum
(
d.SALES
)
for d.FISCALMONTHNAME in
(
[January],
[February],
[March],
[April],
[May],
[June],
[July],
[August],
[September],
[October],
[November],
[December]
)
)
as p
order by 2, 1
If you have a Tally table, you can mock populate S200 for 3 years starts from 2014 for 3 customers:
truncate table S200
insert
S200
select
101 + cast(3 * rand(checksum(newid())) as int),
dateadd(day, cast(3 * 365 * rand(checksum(newid())) as int),
datefromparts(2014, 1, 1)),
case when rand(checksum(newid())) > .6 then 4 else 3 end,
1 + cast(100 * rand(checksum(newid())) as int)
from
Tally
where
Id <= 1000
You may have result like this:
| CUSTNMBR | FISCALYEAR | January | February | March | April | May | June | July | August | September | October | November | December | YearToDate |
|----------|------------|---------|----------|---------|--------|---------|---------|---------|---------|-----------|---------|----------|----------|------------|
| 101 | 2014 | 160.00 | 143.00 | 139.00 | 28.00 | 247.00 | 28.00 | NULL | NULL | NULL | NULL | NULL | NULL | 745.00 |
| 102 | 2014 | 24.00 | 158.00 | -244.00 | -85.00 | 103.00 | 20.00 | NULL | NULL | NULL | NULL | NULL | NULL | -24.00 |
| 103 | 2014 | 123.00 | -167.00 | -6.00 | -30.00 | -53.00 | 15.00 | NULL | NULL | NULL | NULL | NULL | NULL | -118.00 |
| 101 | 2015 | 14.00 | 200.00 | 304.00 | 137.00 | 236.00 | -245.00 | 289.00 | 258.00 | 192.00 | -13.00 | 275.00 | 9.00 | 1656.00 |
| 102 | 2015 | -40.00 | 115.00 | -36.00 | 142.00 | -18.00 | 48.00 | -262.00 | -71.00 | 24.00 | 189.00 | -166.00 | -49.00 | -124.00 |
| 103 | 2015 | 265.00 | -103.00 | 73.00 | -50.00 | 61.00 | -268.00 | -20.00 | -214.00 | -21.00 | 50.00 | -48.00 | -204.00 | -479.00 |
| 101 | 2016 | 207.00 | -201.00 | 34.00 | 397.00 | -156.00 | 267.00 | -272.00 | -156.00 | -61.00 | -98.00 | 575.00 | 107.00 | 643.00 |
| 102 | 2016 | 27.00 | 20.00 | 199.00 | 328.00 | 44.00 | 55.00 | 447.00 | 188.00 | -57.00 | -118.00 | -1.00 | 74.00 | 1206.00 |
| 103 | 2016 | -114.00 | 333.00 | 299.00 | 145.00 | 80.00 | -8.00 | 58.00 | -151.00 | 44.00 | 799.00 | 218.00 | 14.00 | 1717.00 |
| 101 | 2017 | NULL | NULL | NULL | NULL | NULL | NULL | -154.00 | -56.00 | 192.00 | -283.00 | 371.00 | 155.00 | 225.00 |
| 102 | 2017 | NULL | NULL | NULL | NULL | NULL | NULL | 11.00 | -50.00 | 82.00 | 8.00 | 562.00 | -26.00 | 587.00 |
| 103 | 2017 | NULL | NULL | NULL | NULL | NULL | NULL | 294.00 | -93.00 | -51.00 | 29.00 | 322.00 | 392.00 | 893.00 |
Perhaps with certain indexes on those computed columns, it would give even better performance.
I am trying (and failing) to craft a simple SQL query (for SQL Server 2012) that counts the number of occurrences of a value for a given date range.
This is a collection of results from a survey.
So the end result would show there are only 3 lots of values matching '2' and
6 values matching '1'.
Even better if the final result could return 3 values:
MatchZero = 62
MatchOne = 6
MatchTwo = 3
Something Like (I know this is horribly out):
SELECT
COUNT(0) AS MatchZero,
COUNT(1) AS MatchOne,
COUNT(2) As MatchTwo
WHERE dated BETWEEN '2014-01-01' AND '2014-02-01'
I don't need it grouped by date or anything, simply a total value for each.
Any insights would be greatly received.
+------------+----------+--------------+-------------+------+-----------+------------+
| QuestionId | friendly | professional | comfortable | rate | recommend | dated |
+------------+----------+--------------+-------------+------+-----------+------------+
| 3 | 0 | 0 | 0 | 0 | 0 | 2014-02-12 |
| 9 | 0 | 0 | 0 | 0 | 0 | 2014-02-12 |
| 14 | 0 | 0 | 0 | 2 | 0 | 2014-02-13 |
| 15 | 0 | 0 | 0 | 0 | 0 | 2014-01-06 |
| 19 | 0 | 1 | 2 | 0 | 0 | 2014-01-01 |
| 20 | 0 | 0 | 0 | 0 | 0 | 2013-12-01 |
| 21 | 0 | 1 | 0 | 0 | 0 | 2014-01-01 |
| 22 | 0 | 1 | 0 | 0 | 0 | 2014-01-01 |
| 23 | 0 | 0 | 0 | 0 | 0 | 2014-01-24 |
| 27 | 0 | 0 | 0 | 0 | 0 | 2014-01-31 |
| 30 | 0 | 1 | 2 | 0 | 0 | 2014-01-27 |
| 31 | 0 | 0 | 0 | 0 | 0 | 2014-01-11 |
| 36 | 0 | 0 | 0 | 1 | 1 | 2014-01-22 |
+------------+----------+--------------+-------------+------+-----------+------------+
You can use conditional aggregation:
SELECT SUM((CASE WHEN friendly = 0 THEN 1 ELSE 0 END) +
(CASE WHEN professional = 0 THEN 1 ELSE 0 END) +
(CASE WHEN comfortable = 0 THEN 1 ELSE 0 END) +
(CASE WHEN rate = 0 THEN 1 ELSE 0 END) +
(CASE WHEN recommend = 0 THEN 1 ELSE 0 END) +
) AS MatchZero,
SUM((CASE WHEN friendly = 1 THEN 1 ELSE 0 END) +
(CASE WHEN professional = 1 THEN 1 ELSE 0 END) +
(CASE WHEN comfortable = 1 THEN 1 ELSE 0 END) +
(CASE WHEN rate = 1 THEN 1 ELSE 0 END) +
(CASE WHEN recommend = 1 THEN 1 ELSE 0 END) +
) AS MatchOne,
SUM((CASE WHEN friendly = 2 THEN 1 ELSE 0 END) +
(CASE WHEN professional = 2 THEN 1 ELSE 0 END) +
(CASE WHEN comfortable = 2 THEN 1 ELSE 0 END) +
(CASE WHEN rate = 2 THEN 1 ELSE 0 END) +
(CASE WHEN recommend = 2 THEN 1 ELSE 0 END) +
) AS MatchTwo
FROM . . .
WHERE dated BETWEEN '2014-01-01' AND '2014-02-01';
If I understand you correctly, you want to count the zeros, ones and twos for a particular (or each) column in your table. If this is correct, then you could do something like this:
select sum(case when your_column = 0 then 1 else 0 end) as zeros
, sum(case when your_column = 1 then 1 else 0 end) as ones
--- and so on
from your_table
-- where conditions go here
If you want to count the total for more than one column, enclose the needed case...ends in the sum():
sum(
(case when column1 = 0 then 1 else 0 end) +
(case when column2 = 0 then 1 else 0 end)
-- and so on
) as zeros
Going with a simple unpivot you can get the desired result with less coding.
By simply changing the date range the correct count of each question type is counted.
SELECT
RANKING, COUNT(*) AS CNT
FROM
(SELECT
friendly,professional,comfortable,rate,recommend
FROM
your_table
WHERE
dated >= '1/1/1900' AND dated <= '1/1/2015'
) AS U UNPIVOT
(RANKING FOR QUESTION IN (friendly,professional,comfortable,rate,recommend)) AS UNP
GROUP BY
RANKING