Count multiple columns - mysql

I have this table:
Teams:
ID | Size1 | Size2 | Size3 | Size4 | ... (other columns)..
----------------------------------------
1 | L | XL | L | M | ...
----------------------------------------
2 | S | L | S | XXL | ...
----------------------------------------
3 | M | XXL | L | M | ...
----------------------------------------
4 | L | XL | XS | XXL | ...
What is the most effective (and simplest) MySQL query to count all L in table?
I'd like to have only one field in result which is the count of all L in all columns.
EDIT:
Just to clarify little more, in my table there is 152 Ls in first column, 2 in second, 151 in third and 3 in fourth and I expect 308 as result

You can use SUM and CASE to do that:
SELECT
sum(case when Size1 = 'L' then 1 else 0 end) +
sum(case when Size2 = 'L' then 1 else 0 end) +
sum(case when Size3 = 'L' then 1 else 0 end) +
sum(case when Size4 = 'L' then 1 else 0 end)
FROM Teams;
Alternatively instead of CASE, you can use IF:
SELECT
sum(IF(Size1 = 'L',1, 0)) +
sum(IF(Size2 = 'L',1, 0)) +
sum(IF(Size3 = 'L',1, 0)) +
sum(IF(Size4 = 'L',1, 0))
FROM Teams;
This is actually the same.
Edit.
According to Andomar's comment there's even simpler solution:
SELECT
sum(Size1 = 'L') +
sum(Size2 = 'L') +
sum(Size3 = 'L') +
sum(Size4 = 'L')
FROM Teams;
This is correct since true is equal to 1 in MySQL. I've just verified this. ;-)
2nd Edit
Next step to simplify this - only one SUM usage:
SELECT sum(
(Size1 = 'L') +
(Size2 = 'L') +
(Size3 = 'L') +
(Size4 = 'L') )
FROM Teams;

Please try the following query:
SELECT sum(
IF(Size1='L', 1, 0) +
IF(Size2='L', 1, 0) +
IF(Size3='L', 1, 0) +
IF(Size4='L', 1, 0)
) as total FROM Teams

Assuming there can only be one 'L' per row:
select count(*)
from YourTable
where 'L' in (Size1, Size2, ..., SizeN)
Or a normalizing solution, which supports multiple 'L''s per row:
select count(*)
from (
select size1 as size
from YourTable
union all
select size2
from YourTable
union all
select size3
from YourTable
union all
...
)
where size = 'L'

Your WHERE condition is going to be quite large but you could use this:
SELECT count(Size1) + count(size2) AS total WHERE size1 = 'L' OR size2 = 'L'
This solution will count all columns and total based on individual column comparisons.

Related

mysql update column based on another updated column

Note, this question is not same to the MySQL update column based on another column data manipulation
table order
| order_number | payment_amount | refund_amount | refund_status |
| 12 | 100 | 50 | 1 |
refund_status:
0: none refunded;
1: part refunded;
2: all refunded;
update order set refund_amount = refund_amount + 50, refund_status = CASE WHEN payment_amount = refund_amount + 50 THEN 2 ELSE 1 END where order_number = 12;
// refund_amount -> 100, refund_status ->1
Cannot get the right result (refund_amount -> 100, refund_status ->2).
But
update order set refund_amount = refund_amount + 50, refund_status = CASE WHEN payment_amount = refund_amount THEN 2 ELSE 1 END where order_number = 12;
// refund_amount -> 100, refund_status ->2
Can get the right result.
It seems update refund_status besed on the updated refund_amount, is it reliable?
use bracket every you use function case for system readable on your logic code.
update order
set refund_amount = (refund_amount + 50),
refund_status = (CASE WHEN payment_amount = refund_amount + 50 THEN 2 ELSE 1 END)
where order_number = 12;

CASE WHEN IN ({set of numbers})

I need a following case statement in MySQL.
When column value is (1, 2, 5, 7, 14, 17) - return 0, otherwise return 1 and I need to use it in order by clause.
My first impression was to make query like this:
SELECT ... ORDER BY (CASE column WHEN IN (1, 2, 5, 7, 14, 17) THEN 0 ELSE 1 END) DESC
but this obviously fails.
I can write it like this:
SELECT ... ORDER BY (CASE column WHEN 1 THEN WHEN 2 THEN 0 WHEN 5 THEN ... 0 ELSE 1 END) DESC
But I am looking for a more elegant way. Is there any other elegant syntax?
This needs to work
SELECT ...
ORDER BY
CASE WHEN (column IN (1, 2, 5, 7, 14, 17) THEN 0 ELSE 1 END) DESC
Demonstration:
with cte0 as
(
select 120 x from dual union
select 1 from dual union
select 22 from dual union
select 7 from dual
)
select * from cte0
order by (case when x in (22) then 0 else 1 end) desc;
| X |
| --: |
| 1 |
| 120 |
| 7 |
| 22 |
db<>fiddle here
You can use nested query, e.g.:
SELECT B.*
FROM (
SELECT A, CASE WHEN B IN (1, 2, 5, 7, 14, 17) THEN 1 ELSE 0 END AS ORDERING
FROM TABLE
) B
ORDER BY B.ORDERING DESC;

SQL count specific value over multiple columns and rows

I feel as if this should be quite easy, but can't seem to find a solution.
Suppose I have the following table:
|--------||---||---||---||---||---||---||---|
|Company ||q1 ||q2 ||q3 ||q4 ||q5 ||q6 ||q7 |
|--------||---||---||---||---||---||---||---|
|abc ||1 ||2 ||1 ||3 ||2 ||2 ||1 |
|abc ||2 ||2 ||1 ||2 ||3 ||1 ||1 |
|abc ||1 ||1 ||3 ||3 ||1 ||2 ||2 |
|abc ||1 ||2 ||1 ||3 ||0 ||1 ||3 |
I want to count the number of times '1' appears in the table, so the query should, in this case, result with 12. I tried 'hardcoding' it, like the following query. But that just results in the rows containing a 1, so in this case 4. How do I count the number of times '1' occurs, thus resulting in a count of 12?
SELECT COUNT(*)
FROM table
WHERE Company = 'abc'
AND (
q1 = '1'
OR q2 = '1'
OR q3 = '1'
OR q4 = '1'
OR q5 = '1'
OR q6 = '1'
OR q7 = '1'
)
SELECT SUM(
IF(q1 = 1, 1, 0) +
IF(q2 = 1, 1, 0) +
IF(q3 = 1, 1, 0) +
IF(q4 = 1, 1, 0) +
IF(q5 = 1, 1, 0) +
IF(q6 = 1, 1, 0) +
IF(q7 = 1, 1, 0)
)
FROM table
WHERE Company = 'abc'
This is very weird assignment but:
http://sqlfiddle.com/#!9/2e7aa/3
SELECT SUM((q1='1')+(q2='1')+(q3='1')+(q4='1')+(q5='1')+(q6='1')+(q7='1'))
FROM table
WHERE Company = 'abc'
AND '1' IN (q1,q2,q3,q4,q5,q6,q7)
Not so easy, each column needs to be hard-coded. I'd try something using a CASE or DECODE.
SELECT
SUM(
CASE WHEN q1 = 1 THEN 1 ELSE 0 END +
CASE WHEN q2 = 1 THEN 1 ELSE 0 END +
CASE WHEN q3 = 1 THEN 1 ELSE 0 END +
CASE WHEN q4 = 1 THEN 1 ELSE 0 END +
CASE WHEN q5 = 1 THEN 1 ELSE 0 END +
CASE WHEN q6 = 1 THEN 1 ELSE 0 END +
CASE WHEN q7 = 1 THEN 1 ELSE 0 END)
FROM table
WHERE Company = 'abc'
Using a SUM instead of a COUNT will allow the CASE statement to be SUMed.
Use conditional COUNT
SELECT COUNT(case when q1 = '1' then 1 end) +
COUNT(case when q2 = '1' then 1 end) +
COUNT(case when q3 = '1' then 1 end) +
COUNT(case when q4 = '1' then 1 end) +
COUNT(case when q5 = '1' then 1 end) +
COUNT(case when q6 = '1' then 1 end) +
COUNT(case when q7 = '1' then 1 end) as ones_total
FROM table
WHERE Company = 'abc'
For reasons of efficiency I don't recommend actually using this approach; but for learning purposes here's another way you could have broken down the problem along the lines of the way you were thinking about it.
select sum(c) as total_ones
from
(
select count(*) c from table where q1 = 1 union all
select count(*) from table where q2 = 1 union all
select count(*) from table where q3 = 1 union all
select count(*) from table where q4 = 1 union all
select count(*) from table where q5 = 1 union all
select count(*) from table where q6 = 1 union all
select count(*) from table where q7 = 1
) t

Concatenating row values sql server 2008 r2

I have two tables register and att_bottom and I want to display only the students at a certain building who have been tardy based on today's date with the periods separated by a comma.
This is the way the data is displayed when joining both tables:
Student ID | Building | Period | Grade
12345 2 1 11
12345 2 5 11
43210 2 1 12
I want this:
Student ID | <u>Building | Period | Grade
12345 2 1,5 11
43210 2 1 12
This is my query:
select r.STUDENT_ID,
r.BUILDING ,
(select ab.attendancePeriod + ','
from att_bottom ab
where ab.STUDENT_ID = r.student_id
and ab.building = '2'
and ab.attendance_c ='T'
and ab.SCHOOL_YEAR =2014
CONVERT(date,ab.attendance_date,102) = convert(date,getdate(),102)
FOR XML PATH ('') ) AS PERIODS,
r.GRADE
FROM register r
where r.CURRENT_STATUS = 'A'
and r.BUILDING ='2'
I'm getting all the students at building 2 and even if they don't have an attedance_c of T; a NULL value for Periods is being retrieved:
Student ID | Building | Period | Grade
12345 2 1 , 5 11
43210 2 1 , 12
95687 2 NULL 09
78417 2 NULL 10
20357 2 NULL 11
I have tried and ab.attendancePeriod is Not NULL and I still get the same results.
Any thoughts?
The outer query doesn't listen to any filters in the subquery; it will return NULL for any rows that aren't matched by the join conditions. You need to filter differently. Here is one way (this also eliminates the errant trailing comma, and avoids comparing dates by converting them expensively to strings):
;WITH x AS
(
SELECT DISTINCT s = r.Student_ID, r.building,
p = ab.attendancePeriod, r.grade
FROM dbo.Register AS r
INNER JOIN dbo.att_bottom AS ab
ON r.Student_ID = ab.Student_ID
AND r.building = ab.building
WHERE ab.building = '2'
AND ab.attendance_c = 'T'
AND ab.SCHOOL_YEAR = 2014
AND ab.attendance_date >= CONVERT(DATE, GETDATE())
AND ab.attendance_date < DATEADD(DAY, 1, CONVERT(DATE, GETDATE()))
AND r.building = '2'
AND r.CURRENT_STATUS = 'A'
)
SELECT DISTINCT
[Student ID] = x.s,
x.building,
Period = STUFF((SELECT ',' + x2.p FROM x AS x2 WHERE x2.s = x.s
FOR XML PATH(''),
TYPE).value(N'./text()[]',N'nvarchar(max)'),1,1,''),
x.grade
FROM x;
Another way:
SELECT DISTINCT
r.Student_ID,
r.building,
Period = STUFF(b.p.value(N'./text()[1]', N'nvarchar(max)'),1,1,''),
r.grade
FROM dbo.Register AS r
CROSS APPLY
(
SELECT p = ',' + ab.attendancePeriod
FROM dbo.att_bottom AS ab
WHERE ab.building = '2'
AND ab.attendance_c = 'T'
AND ab.SCHOOL_YEAR = 2014
AND ab.attendance_date >= CONVERT(DATE, GETDATE())
AND ab.attendance_date < DATEADD(DAY, 1, CONVERT(DATE, GETDATE()))
AND ab.student_id = r.student_id
AND ab.building = r.building
FOR XML PATH(''),TYPE
) AS b(p)
WHERE b.p IS NOT NULL
AND r.building = '2'
AND r.CURRENT_STATUS = 'A';
Move the AS PERIODS select to be an inner join to r.

MySQL matrix multiplication

I am trying to write matrix multiplication for MySQL and am kinda stuck:
basically, my matrices are stored in format
[row#, column#, matrixID, value], so for example matrix [3 x 2] would be something like:
[row#, column#, matrixID, value]
1 1 mat01 1
1 2 mat01 2
1 3 mat01 3
2 1 mat01 4
2 2 mat01 5
2 3 mat01 6
being equivalent to: [[1 2 3],[4 5 6]]
following does calculation of single element of matrix1 * matrix2 quite well:
SELECT SUM(row1.`val` * col2.`val`)
FROM matValues row1
INNER JOIN `matValues` col2
WHERE row1.`row` = 1 AND row1.`mID`='matrix1' AND
col2.`mID`='matrix2' AND col2.`col` = 1 AND row1.col = col2.row
wrapping this into function and then using another function to iterate over row and column numbers might work, but I have problems with generating this set of numbers and iterating over them using SQL.
Any advice / suggestions are welcome
Try:
select m1.`row#`, m2.`column#`, sum(m1.value*m2.value)
from matValues m1
join matValues m2 on m2.`row#` = m1.`column#`
where m1.matrixID = 'mat01' and m2.matrixID = 'mat02'
group by m1.`row#`, m2.`column#`
Example here.
(Replace 'mat01' and 'mat02' with suitable matrixID values.)
You can do the entire calculation in SQL. You only give an example with a single matrix, which because it is not square, cannot be multiplied by itself.
Here is the idea:
SELECT mout.row, mout.col, SUM(m1.value*m2.value)
FROM (select distinct row from matValues cross join
select distinct COL from matValues
) mout left outer join
matValues m1
on m1.row = mout.row left outer join
matValues m2
on m2.col = mout.col and
m2.row = m1.col
I know this is SQL-Server syntax, but it should give you a start on the corresponding MySql syntax. The sparse matrix nature seems to handle well.
with I as (
select * from ( values
(1,1, 1),
(2,2, 1),
(3,3, 1)
) data(row,col,value)
)
,z_90 as (
select * from ( values
(1,2, 1),
(2,1,-1),
(3,3, 1)
) data(row,col,value)
)
,xy as (
select * from ( values
(1,2, 1),
(2,1, 1),
(3,3, 1)
) data(row,col,value)
)
,x_90 as (
select * from ( values
(1,1, 1),
(2,3, 1),
(3,2,-1)
) data(row,col,value)
)
select
'I * z_90' as instance,
a.row,
b.col,
sum( case when a.value is null then 0 else a.value end
* case when b.value is null then 0 else b.value end ) as value
from I as a
join z_90 as b on a.col = b.row
group by a.row, b.col
union all
select
'z_90 * xy' as instance,
a.row,
b.col,
sum( case when a.value is null then 0 else a.value end
* case when b.value is null then 0 else b.value end ) as value
from z_90 as a
join xy as b on a.col = b.row
group by a.row, b.col
union all
select
'z_90 * x_90' as instance,
a.row,
b.col,
sum( case when a.value is null then 0 else a.value end
* case when b.value is null then 0 else b.value end ) as value
from z_90 as a
join x_90 as b on a.col = b.row
group by a.row, b.col
order by instance, a.row, b.col
yields:
instance row col value
----------- ----------- ----------- -----------
I * z_90 1 2 1
I * z_90 2 1 -1
I * z_90 3 3 1
z_90 * x_90 1 3 1
z_90 * x_90 2 1 -1
z_90 * x_90 3 2 -1
z_90 * xy 1 1 1
z_90 * xy 2 2 -1
z_90 * xy 3 3 1
However, I suggest you also check out performing this on your graphics card. NVIDIA has a good example of implementing matrix multiplication in theri C Programming Guide.