MySQL How to count columns containing specified column value - mysql

I have the table xyz
ID day1 day2 day3 day4
1 A A P P
2 A A A P
3 A A A A
4 A P P P
I want to be able to query this and return the ID with the number of columns that have A as their value in that row. So the result would look like this:
ID Count
1 2
2 3
3 4
4 1

Here is a trick you can use involving string concatenation:
SELECT
ID,
CHAR_LENGTH(CONCAT(day1, day2, day3, day4)) -
CHAR_LENGTH(REPLACE(CONCAT(day1, day2, day3, day4), 'A', '')) AS Count
FROM yourTable
ORDER BY ID;
Demo
If you want to count other letters as well, just duplicate the logic I have for the letter A, e.g. for L we can try:
CHAR_LENGTH(CONCAT(day1, day2, day3, day4)) -
CHAR_LENGTH(REPLACE(CONCAT(day1, day2, day3, day4), 'L', ''))

This is simple to accomplish applying case to all columns and usmming them up! Try below:
select id,
case day1 when 'A' then 1 else 0 end +
case day2 when 'A' then 1 else 0 end +
case day3 when 'A' then 1 else 0 end +
case day4 when 'A' then 1 else 0 end `CountA`,
case day1 when 'L' then 1 else 0 end +
case day2 when 'L' then 1 else 0 end +
case day3 when 'L' then 1 else 0 end +
case day4 when 'L' then 1 else 0 end `CountL`,
case day1 when 'P' then 1 else 0 end +
case day2 when 'P' then 1 else 0 end +
case day3 when 'P' then 1 else 0 end +
case day4 when 'P' then 1 else 0 end `CountP`
from Tbl

Related

MySQL SUM with CASE choose latest record by date

I've got the SUM CASE statements working properly. The issue is that I have multiple records with similar criteria, so I'd like to select the latest record by date.
SELECT
SUM(CASE WHEN planning like 'Rotation%' THEN 1 ELSE 0 END +
CASE WHEN assessmentanddata like 'Collects%' THEN 1 else 0 END +
CASE WHEN path like 'Same%' THEN 1 else 0 END +
CASE WHEN place like 'Move%' THEN 1 else 0 END +
CASE WHEN pace like 'Timer%' THEN 1 else 0 END +
CASE WHEN classroommanagement like 'Restating%' THEN 1 else 0 END +
CASE WHEN teacherrole like 'Mini%' THEN 1 else 0 END +
CASE WHEN studentengagement like 'Follow%' THEN 1 else 0 END +
CASE WHEN studentcollaboration like 'Collects%' THEN 1 else 0 END +
CASE WHEN technology like 'Technology%' THEN 1 else 0 END) AS p1
from ruberic where schoolId = 1
A sample from the table will be these 3 columns of DATE, SCHOOLID, and TEACHERID:
2016-12-05 1 1 -> This record will be fine
2016-12-05 1 4 -> Select only this when compared with the record below
2016-12-05 1 4
Building on what I see (I don't see the field name for date so assumed date)
This uses a correlates subquery and an exists statement to identify the max(date) for each teacherID and school and then limits the main dataset by this subset through the coloration.
SELECT
SUM(CASE WHEN planning like 'Rotation%' THEN 1 ELSE 0 END +
CASE WHEN assessmentanddata like 'Collects%' THEN 1 else 0 END +
CASE WHEN path like 'Same%' THEN 1 else 0 END +
CASE WHEN place like 'Move%' THEN 1 else 0 END +
CASE WHEN pace like 'Timer%' THEN 1 else 0 END +
CASE WHEN classroommanagement like 'Restating%' THEN 1 else 0 END +
CASE WHEN teacherrole like 'Mini%' THEN 1 else 0 END +
CASE WHEN studentengagement like 'Follow%' THEN 1 else 0 END +
CASE WHEN studentcollaboration like 'Collects%' THEN 1 else 0 END +
CASE WHEN technology like 'Technology%' THEN 1 else 0 END) AS p1
FROM
ruberic R1
WHERE
schoolId = 1
AND EXISTS (SELECT Null
FROM ruberic r2
WHERE R2.SchoolID = R1.SchoolID
AND R2.TeacherID = R1.TeacherID
GROUP BY SchoolID, TeacherID
HAVING R1.Date = MAX(R2.Date) )

How to count non null fields?

I need to get the count of fields where the value is not null.
My table
city id_no no1 no2 no3
chn A12 2158
chn A13 8181 8182 8183
chn A14 19138
I need to get the count of fields set for no1, ..., no3
My query
SELECT
count(id_no) as total_id,
(count(no1) +
count(no2) +
count(no3)) as c_count
FROM table
WHERE city='chn';
My output
total_id c_count
3 9
Expected:
total_id c_count
3 5
I am expecting 5 instead of 9, since 5 fields are not null.
OR you can simply do this to avoid NULL or ' ' data
SELECT
count(id_no) as total_id,
(count(CASE WHEN no1 > 0 THEN no1 ELSE NULL END) +
count(CASE WHEN no2 > 0 THEN no2 ELSE NULL END) +
count(CASE WHEN no3 > 0 THEN no3 ELSE NULL END)) as c_count
FROM table
WHERE city='chn';
SELECT
count(id_no) as total_id,
(case when count(no1)='' or count(no1) is null then 0 else count(no1) end +
case when count(no2)='' or count(no2) is null then 0 else count(no2) end +
case when count(no3)='' or count(no3) is null then 0 else count(no3) end +
case when count(no4)='' or count(no4) is null then 0 else count(no4) end +
case when count(no5)='' or count(no5) is null then 0 else count(no5) end +
case when count(no6)='' or count(no6) is null then 0 else count(no6) end +
case when count(no7)='' or count(no7) is null then 0 else count(no7) end +
case when count(no8)='' or count(no8) is null then 0 else count(no8) end +
case when count(no9)='' or count(no9) is null then 0 else count(no9) end +
case when count(no10)='' or count(no10) is null then 0 else count(no10) end
) as c_count
FROM table
WHERE city='chn';
I am getting same output as you want please check here i provide my screenshot
SELECT count(id_no) as total_id,
count(CASE WHEN `nol`!="" THEN 1 END) as no1
FROM `table` where city='chn'
try like this
select count(distinct a.`id_no`),count(*) from
(
select `id_no`,`no1` as `non` from table WHERE city='chn'
union all
select `id_no`,`no2` as `non` from table WHERE city='chn'
union all
select `id_no`,`no3` as `non` from table WHERE city='chn'
)a where a.`non` is not null

MySQL CASE WHEN where clause causes failure

I have a complex query that does multiple matches across multiple columns and then orders by relevance.
Everything works fine UNTIL I add WHERE 'rank' > 0
This then returns an empty results set.
If I remove the 'WHERE' statement then I can see all results with the highest matches at the top.
Could someone help me work out 'WHERE' :-D I am going wrong!!
SELECT *, CASE WHEN companyName = 'gfdgfs' THEN 2 ELSE 0 END
+ CASE WHEN companyName LIKE '%gfdgfs%' THEN 1 ELSE 0 END
+ CASE WHEN companyName = 'potato' THEN 2 ELSE 0 END
+ CASE WHEN companyName LIKE '%potato%' THEN 1 ELSE 0 END
+ CASE WHEN address1 = 'gfdgfs' THEN 2 ELSE 0 END
+ CASE WHEN address1 LIKE '%gfdgfs%' THEN 1 ELSE 0 END
+ CASE WHEN address1 = 'potato' THEN 2 ELSE 0 END
+ CASE WHEN address1 LIKE '%potato%' THEN 1 ELSE 0 END
AS rank
FROM clients
WHERE rank > 0
ORDER BY rank
EDIT
I removed the single quotes around the rank word and now get 'unknown column rank in where clause'
Remove single quotes from rank and try. Anyway, I don't think MySQL would support WHERE clause with aliases - check this.
Use HAVING rather than WHERE:
SELECT *, CASE WHEN companyName = 'gfdgfs' THEN 2 ELSE 0 END
+ CASE WHEN companyName LIKE '%gfdgfs%' THEN 1 ELSE 0 END
+ CASE WHEN companyName = 'potato' THEN 2 ELSE 0 END
+ CASE WHEN companyName LIKE '%potato%' THEN 1 ELSE 0 END
+ CASE WHEN address1 = 'gfdgfs' THEN 2 ELSE 0 END
+ CASE WHEN address1 LIKE '%gfdgfs%' THEN 1 ELSE 0 END
+ CASE WHEN address1 = 'potato' THEN 2 ELSE 0 END
+ CASE WHEN address1 LIKE '%potato%' THEN 1 ELSE 0 END
AS rank
FROM clients
HAVING rank > 0
ORDER BY rank
Try this:
SELECT *
FROM (SELECT *, CASE WHEN companyName = 'gfdgfs' THEN 2 ELSE 0 END
+ CASE WHEN companyName LIKE '%gfdgfs%' THEN 1 ELSE 0 END
+ CASE WHEN companyName = 'potato' THEN 2 ELSE 0 END
+ CASE WHEN companyName LIKE '%potato%' THEN 1 ELSE 0 END
+ CASE WHEN address1 = 'gfdgfs' THEN 2 ELSE 0 END
+ CASE WHEN address1 LIKE '%gfdgfs%' THEN 1 ELSE 0 END
+ CASE WHEN address1 = 'potato' THEN 2 ELSE 0 END
+ CASE WHEN address1 LIKE '%potato%' THEN 1 ELSE 0 END
AS rank
FROM clients
) AS A
WHERE rank > 0
ORDER BY rank;

count the numbers of differences in each columns with data reference impossible?

I need to count the sum of the differences between a set of known data. The equivalent in php is
(count(array_diff_assoc($array1)). Is this possible with Mysql? I have a set of data to compare with each others field column in the table.
my data to compare is columnA : 3, columnB : 6, columnC : 4
the test table is :
ID columnA columnB columnC
1 2 6 1
2 6 1 3
3 3 6 4
result expected :
ID numbersofdifferences
3 0
1 2
2 3
thanks for any help,
Jesisca
This is not necessarily the cleanest but you could use an aggregate function with a CASE expression:
select id,
sum(case when columna = 3 then 0 else 1 end) +
sum(case when columnb = 6 then 0 else 1 end) +
sum(case when columnc = 4 then 0 else 1 end) TotalDiff
from yourtable
group by id;
See SQL Fiddle with Demo.
Edit, this could be done without the aggregate function as well:
select id,
(case when columna = 3 then 0 else 1 end) +
(case when columnb = 6 then 0 else 1 end) +
(case when columnc = 4 then 0 else 1 end) TotalDiff
from yourtable;
See Demo
There isn't a function built in to do something like that, but you could do it manually.
select
id,
case columnA when $columnA then 1 else 0 end +
case columnB when $columnB then 1 else 0 end +
case columnC when $columnC then 1 else 0 end differences
from
myTable
But if you want them in order, you'll want a subselect
select * from
(
select
id,
case columnA when $columnA then 1 else 0 end +
case columnB when $columnB then 1 else 0 end +
case columnC when $columnC then 1 else 0 end differences
from
myTable
) sqlRequiresNameHere
order by differences

Comma Separated Value to Multiple BIT Columns

Hy , I have multiple values and i need a list of checks
ex:
1,2,4,
3,4, should be :
day1 day2 day3 day4
_1____1____0____1
_0____0____1____1
one method is
CAST(CASE WHEN PATINDEX('1,', [day]) > 0 THEN 1 ELSE 0 END AS BIT) as [day1],
CAST(CASE WHEN PATINDEX('2,', [day]) > 0 THEN 1 ELSE 0 END AS BIT) as [day2],
CAST(CASE WHEN PATINDEX('3,', [day]) > 0 THEN 1 ELSE 0 END AS BIT) as [day3],
CAST(CASE WHEN PATINDEX('4,', [day]) > 0 THEN 1 ELSE 0 END AS BIT) as [day4]
please help me with a better method because i have multiple columns
thanks
You can use a string split function of your choice with pivot.
declare #T table
(
ID int identity,
day varchar(20)
)
insert into #T values
('1,2,4,'),
('3,4,')
select isnull(P.[1], 0) as day1,
isnull(P.[2], 0) as day2,
isnull(P.[3], 0) as day3,
isnull(P.[4], 0) as day4
from
(
select T.ID, S.s, 1 as x
from #T as T
cross apply dbo.Split(',', T.day) as S
) as T
pivot (min(T.x) for T.s in ([1],[2],[3],[4])) as p
Result:
day1 day2 day3 day4
1 1 0 1
0 0 1 1
You could use the split function outlined here and then pivot the values into columns.
OR!
This answer looks like the same thing you're trying to do.
Use a second table to store valid days and then query on it. See this fiddle.
EDIT
See updated fiddle, or code below:
create table test (day1 varchar(8), day2 varchar(8), day3 varchar(8), day4 varchar(8));
insert into test (day1, day2, day3, day4) values ('day1', 'day2', 'day3', 'day4');
create table valid_days (valid_day_no int);
insert into valid_days values (1), (2), (4);
select cast (case when exists(select 1 from valid_days where valid_day_no = substring(day1, 4, len(day1))) then 1 else 0 end as bit) day1,
cast (case when exists(select 1 from valid_days where valid_day_no = substring(day2, 4, len(day2))) then 1 else 0 end as bit) day2,
cast (case when exists(select 1 from valid_days where valid_day_no = substring(day3, 4, len(day3))) then 1 else 0 end as bit) day3,
cast (case when exists(select 1 from valid_days where valid_day_no = substring(day1, 4, len(day4))) then 1 else 0 end as bit) day4
from test;
Note that SQL is a fixed column language, you need to use a programming language to dynamically build variable length column queries.