counting null data in MySQL - mysql

let say i have one table, which have data like:
name status
bob single
bob single
jane null
tina null
shane married
i want if status "single or data null" it means single. so if data empty script can read it as single and can count together.
so i can show result like:
Single Married
3 1
i have tried with this and it doesnt work:
SELECT SUM(IF(status='single',1,0)) AS Single,
SUM(IF(status='married',1,0)) AS Married
FROM table

Use:
SELECT SUM(CASE WHEN x.status = 'single' OR x.status IS NULL THEN 1 ELSE 0 END) AS single,
SUM(CASE WHEN x.status = 'married' THEN 1 ELSE 0 END) AS married
FROM (SELECT DISTINCT
t.name,
t.status
FROM YOUR_TABLE t) x

If you know there are only 'single', 'married', and null as options, this will work:
SELECT SUM(IF(status!='married',1,0)) AS Single,
SUM(IF(status='married',1,0)) AS Married
FROM table
Otherwise try
SELECT SUM(IF(status='single' OR status is null,1,0)) AS Single,
SUM(IF(status='married',1,0)) AS Married
FROM table

SELECT SUM(IF(status='single' OR status IS NULL,1,0)) AS Single,
SUM(IF(status='married',1,0)) AS Married
FROM table

Related

How can I get true if there is at least one specific value?

I have a table like this:
user_due_diligence
user_id
cellphone
national_id
postal_code
5
approved
in_progress
in_progress
5
in_progress
approved
not_investigated
5
approved
not_investigated
not_investigated
I want to get 1 row per user_id and either 0 or 1 if there is at least one approved record or not. So the expected result is:
user_id
cellphone
national_id
postal_code
5
1
1
0
Any idea how can I do that?
I know the query should include group by user_id, and case when x = "approved", but I don't know the exact syntax.
in this query I used SUM() and CASE WHEN to match the cases when cellphone, national_id or postal_code equals approved when it's true I add 1 to the summary for each one of them, and at the end you need to group by the user_id to get one result per user_id.
SELECT user_id, SUM(CASE When cellphone LIKE 'approved' THEN 1 ELSE 0 END) AS cellphone ,
SUM(CASE When national_id like 'approved' THEN 1 ELSE 0 END ) AS national_id ,
SUM(CASE WHEN postal_code like 'approved' THEN 1 ELSE 0 END) AS postal_code
FROM user_due_diligence
GROUP BY user_id;

Display sum of each element in a column using sql?

I have simple data from database looks like this
ID sid targetbuttonname
1 ab23sve Yes
2 ab23sve Yes
3 ab23sve Yes
4 ab23sve Yes
5 z32b2367 no
6 zb23sve no
7 pb23sve Yes
I want to display the sum of session, the sum of yes, the sum of no using sql;
eg sum of yes should be 5 etc
I tried something like this
select sum(sid), count(targetbuttoname) as yes, count(targetbuttoname) as no from events
What is the right way to display what I want?
Presumably, you want to count these things. So, I would guess:
select count(*) as num_rows,
count(distinct sid) as num_sessions,
sum( targetbuttonname = 'yes' ) as num_yes,
sum( targetbuttonname = 'no' ) as num_no
from events;
Here is a db<>fiddle.
if you want to count number of yes and no then you can use case when
select sum(case when targetbuttoname='yes' then 1 else 0 end) as yes,
sum(case when targetbuttoname='no' then 1 else 0 end) as no from events

MySQL Select find similar item that has stock

I have this resultset of my table of products, while trying to return correct results in the last two columns, similar_sku_exists and similar_sku_in_stock.
The goal is, to first determine whether a similar sku exists in the table and return yes/no.
second to determine if either one of the similar skus have stock and return that sku name/s.
A similar sku is defined by the same sku name + first letter of grade.
Eg, all instances of "ABC-11-A" will be similar as they bear the same condition of new. Likewise "ABC-11-B" will be similar in that they are all refurb condition.
id sku condition grade stock similar_sku_exists similar_sku_in_stock
1 ABC-11-A1 new A1 0 yes ABC-11-A2
2 ABC-11-A2 new A2 10 yes
3 ABC-11-B1 refurb B1 10 yes
4 ABC-11-B2 refurb B2 0 yes ABC-11-B1|ABC-11-B2-LP
5 ABC-11-B2-LP refurb B2-LP 10 yes
6 DEF-2-F-A1 new A1 0 no
7 DEF-2-G-B1 refurb B1 10 yes
8 DEF-2-G-B2 refurb B2 0 yes DEF-2-G-B1
So far i have this query but that dosn'nt seem to return correct results
select
id,
sku,
`condition`,
grade,
stock,
case when left(p.sku, length(p.sku)-length(p.grade)+1)
in (select left(p.sku, length(p.sku)-length(p.grade)+1))
then 'yes' else 'no' end as similar_sku_exists,
if(p.stock = 0,
case when left(p.sku, length(p.sku)-length(p.grade)+1)
in (select left(p.sku, length(p.sku)-length(p.grade)+1) and p.stock >0
)
then group_concat(distinct(p.sku) separator '|')
else '' end,'') as similar_sku_in_stock
from products as p
Much appreciated any tought
Here is a method to get the similar skus in stock:
select p.*,
(select group_concat(p2.sku)
from products p2
where substring_index(p2.sku, '-', 1) = substring_index(p.sku, '-', 1) and
left(subsctring_index(p2.sku, '-', -1), 1) = left(substring_index(p.sku, '-', -1), 1) and
p2.sku <> p.sku and
stock > 0
) similar_skus_in_stock
from products p;
A similar query can be used to determine if similar skus exist.

MySQL return min value but not null

I have a table where there are columns students and grade obtained(A-F). A student can appear for test more than once. Sometimes students register but do not appear for test so the grade is not entered but student record entry is made.
I want to get best grade of each student. When I do min(grade) if there is any record with null, null gets selected instead of 'A-F' which indicate proper results. I want to get min of grade if grade exists or null if there are no grades.
SELECT `name`,min(grade) FROM `scores` group by `name`
Id | Name | Grade
1 | 1 | B
2 | 1 |
3 | 1 | A
4 | 2 | C
5 | 2 | D
For name 1 it is fetching second record not the third one having 'A'.
As per the conversations in the comments, the easiest solution may be to convert your empty strings to null, and let the builtin min function do the heavy lifting:
ALTER TABLE scores MODIFY grade VARCHAR(1) NULL;
UPDATE scores
SET grade = null
WHERE grade = '';
SELECT name, MIN(grade)
FROM scores
GROUP BY name
If this is not possible, a dirty trick you could use is to have a case expression convert the empty string to a something you know will come after F:
SELECT name,
MIN(CASE grade WHEN '' THEN 'DID NOT PARTICIPATE' ELSE grade END)
FROM scores
GROUP BY name
And if you really need the empty string back, you can have another case expression around the min:
SELECT name, CASE best_grade WHEN 'HHH' THEN '' ELSE best_grade END
FROM (SELECT name,
MIN(CASE grade WHEN '' THEN 'HHH' ELSE grade END) AS
best_grade
FROM scores
GROUP BY name) t
Change your query slightly to -
SELECT `name`,min(grade) FROM `scores` WHERE grade <> "" group by `name`
If the name has a grade/s assigned to it then the lowest will be returned else the resultset will be null

something like "group by" for columns?

I have table like this:
+----+---------+---------+--------+
| id | value_x | created | amount |
+----+---------+---------+--------+
value_x is set of six strings, lets say "one", "two", "three", etc.
I need to create report like this:
+--------------+-------------------------+-------------------+----------------------+
| day_of_month | "one" | "two" | [etc.] |
+--------------+-------------------------+-------------------+----------------------+
| 01-01-2011 | "sum(amount) where value_x = colum name" for this specific day |
+--------------+-------------------------+-------------------+----------------------+
Most obvious solution is:
SELECT SUM(amount), DATE(created) FROM `table_name` WHERE value_x=$some_variable GROUP BY DATE(created)
And loop this query six times with another value for $some_variable in every iteration, but I'm courious if is it possible to do this in single query?
What you're asking is called a "pivot table" and is typically achieved as below. The idea is for each potential value of value_x you either produce a 1 or 0 per row and sum 1's and 0's to get the sum for each value.
SELECT
DATE(created),
SUM(CASE WHEN value_x = 'one' THEN SUM(amount) ELSE 0 END) AS 'one',
SUM(CASE WHEN value_x = 'one' THEN SUM(amount) ELSE 0 END) AS 'two',
SUM(CASE WHEN value_x = 'one' THEN SUM(amount) ELSE 0 END) AS 'three',
etc...
FROM table_name
GROUP BY YEAR(created), MONTH(created), DAY(created)
This will come close:
SELECT
s.day_of_month
,GROUP_CONCAT(CONCAT(s.value_x,':',s.amount) ORDER BY s.value_x ASC) as output
FROM (
SELECT DATE(created) as day_of_month
,value_x
,SUM(amount) as amount
FROM table1
GROUP BY day_of_month, value_x
) s
GROUP BY s.day_of_month
You will need to read the output and look for the value_x prior to the : to place the items in the proper column.
The benefit of this approach over #Michael's approach is that you do not need to know the possible values of field value_x beforehand.