Get the earliest time if rows are more than 1 - mysql

I need help with some MySQL pain in the ****... Anyway, i got the following sql :
SELECT id,count(*),
CASE
WHEN count(*) > 1 THEN
// I need the minimal `taskdate_time` column from the selected rows
// where a certain boolean is active
ELSE taskdate_time
END
FROM timehistory th
WHERE `send`=true
GROUP BY date_format(taskdate_time, "%Y-%m-%d"), user_id
As described in the comments, i need to get the earliest time out for the two rows where a column called removed is not FALSE
How do i achieve this?
My columns are :
`id` - int
`taskdateuser_id` int
`user_id` int
`changed_by` int
`batch_id` int
`taskdate_time` timestamp
`send` tinyint
`isread` tinyint
`update` tinyint
`removed` tinyint
Many thanks in advance!!!
EDIT:
I might explain it a bit more. If i got the following table rows :
The red marked rows are captured by the CASE count(*) > 1, because there are 2 rows returned by the group by. Then i need to to a SELECT from that 2 captured rows where removed=false and min(taskdate_time). So if 4 rows are returned for that group by, and 2 of the rows are removed=false and the other are removed=true then i need to do a subselect for the minimum taskdate_time that 2 rows where removed=false.

SELECT id,
count(*),
CASE WHEN count(*) > 1
THEN (SELECT MAX(taskdate_time) FROM timehistory f WHERE f.id = th.id AND removed = 0)
ELSE taskdate_time
END
FROM timehistory th
WHERE `send` = true
GROUP BY date_format(taskdate_time, "%Y-%m-%d"), user_id

You could try something like this:
SELECT TH.user_id, COUNT(*),
CASE WHEN COUNT(*) > 1
THEN MIN(IF(TH.removed, TH.taskdate_time, NULL))
ELSE TH.taskdate_time
END
FROM TimeHistory TH
...
Sample Fiddle Demo
However, if COUNT > 1 AND there aren't any records where TH.removed is true, then this will return NULL for that value. What should it return in those cases?
--EDIT--
In response to comments, then this should work just wrapping it with COALESCE:
COALESCE(
CASE
WHEN COUNT(*) > 1
THEN MIN(IF(TH.removed, TH.taskdate_time, NULL))
ELSE TH.taskdate_time
END, MIN(TH.taskdate_time))

Related

Check for all null values in a GROUP BY [duplicate]

This question already has answers here:
MySQL AVG() return 0 if NULL
(3 answers)
Closed last month.
I have the following structre
id val
1 ...
.
.
2 ...
.
.
3 null
3 null
3 null
4 ...
.
.
Basically each id has multiple no. of values. And an id has either all values as integers or all values as null
What I want is to perform an aggregate (like AVG) on val group by id. If that id has null values, I want to put 5 there.
#1
SELECT id, (CASE SUM(val) WHEN null THEN 5 ELSE AVG(val) END) AS ac FROM tt GROUP BY id
> executes ELSE even for id = 3
In CASE, there should be an aggregate function that when done on null values give null.
I checked SUM and MAX like
SELECT SUM(val) FROM tt WHERE id = 3
> null
and it gives null here but doesn't work in main statement. I guess it is related to the type of equality and hence tried WHEN IS NULL but its a syntax error.
Also, is there some more standard way of indicating group of values as all null rather than using SUM or MAX.
You can use if condition :
select id, If(sum(val) is null, 5, AVG(val)) as average
FROM tt
group by id
check here : https://dbfiddle.uk/Uso9nNTM
The exact problem with your CASE expression is that to check for null in MySQL we have to use IS NULL rather than equality. So use this version:
CASE WHEN SUM(val) IS NULL THEN 5 ELSE AVG(val) END
But we might as well just use COALESCE() to assign an average of 5 for those id groups having all null values.
SELECT id, COALESCE(AVG(val), 5) AS avg_val
FROM tt
GROUP BY id;
Note that the AVG() function by default ignores nulls. Therefore, the expression AVG(val) would only be null if every record in an id group were having null for val.

mysql count distinct value

I have trouble wondering how do I count distinct value. using if on the select column
I have SQLFIDDLE here
http://sqlfiddle.com/#!2/6bfb9/3
Records shows:
create table team_record (
id tinyint,
project_id int,
position varchar(45)
);
insert into team_record values
(1,1, 'Junior1'),
(2,1, 'Junior1'),
(3,1, 'Junior2'),
(4,1, 'Junior3'),
(5,1, 'Senior1'),
(6,1, 'Senior1'),
(8,1, 'Senior2'),
(9,1, 'Senior2'),
(10,1,'Senior3'),
(11,1, 'Senior3'),
(12,1, 'Senior3')
I need to count all distinct value, between Junior and Senior column.
all same value would count as 1.
I need to see result something like this.
PROJECT_ID SENIOR_TOTAL JUNIOR_TOTAL
1 3 3
mysql query is this. but this is not a query to get the result above.
SELECT
`team_record`.`project_id`,
`position`,
SUM(IF(position LIKE 'Senior%',
1,
0)) AS `Senior_Total`,
SUM(IF(position LIKE 'Junior%',
1,
0)) AS `Junior_Total`
FROM
(`team_record`)
WHERE
project_id = '1'
GROUP BY `team_record`.`project_id`
maybe you could help me fix my query above to get the result I need.
thanks
I think you want this:
SELECT
project_id,
COUNT(DISTINCT CASE when position LIKE 'Senior%' THEN position END) Senior_Total,
COUNT(DISTINCT CASE when position LIKE 'Junior%' THEN position END) Junior_Total
FROM team_record
WHERE project_id = 1
GROUP BY project_id
The CASE will return a null if the WHEN is false (ie ELSE NULL is the default, which I omitted for brevity), and nulls aren't counted in DISTINCT.
Also, unnecessary back ticks, brackets and qualification removed.

Counting total and true condition lines

How to count the number of lines in a table and the number of lines where a certain condition is true without resorting to subselects like this:
create table t (a integer);
insert into t (a) values (1), (2), (null);
select
(select count(*) from t) as total_lines,
(select count(*) from t where a = 1) as condition_true
;
total_lines | condition_true
-------------+----------------
3 | 1
select count(*) as total_lines, count(a = 1 or null) as condition_true
from t
;
total_lines | condition_true
-------------+----------------
3 | 1
It works because:
First while count(*) counts all lines regardless of anything, count(my_column) will count only those lines where my_column is not null:
select count(a) as total
from t
;
total
-------
2
Second (false or null) returns null so whenever my condition is not met it will return null and will not be counted by count(condition or null) which only counts not nulls.
Use SUM(condition)!
select
count(*) as total_lines,
sum(a = 1) as condition_true
from t
See it working here.
This works because in mysql, true is 1 and false is 0, so the sum() of a condition will add 1 when it's true and 0 when it's false - which effectively counts the number of times the condition is true.
Many people falsely believe you need a case statement, but you don't with mysql (you do with some other databases)
this can be easily done using a condition inside count. I don't know if its the optimized method of doing it but it gets the work done
you can do it as follows
select count(*) as total_lines, COUNT(CASE WHEN a = 1 THEN 1 END) as condition_true from t
you can check it here
sqlFiddle

Comparing 2 Columns in same table

I need to compare 2 columns in a table and give 3 things:
Count of rows checked (Total Rows that were checked)
Count of rows matching (Rows in which the 2 columns matched)
Count of rows different (Rows in which the 2 columns differed)
I've been able to get just rows matching using a join on itself, but I'm unsure how to get the others all at once. The importance of getting all of the information at the same time is because this is a very active table and the data changes with great frequency.
I cannot post the table schema as there is a lot of data in it that is irrelevant to this issue. The columns in question are both int(11) unsigned NOT NULL DEFAULT '0'. For purposes of this, I'll call them mask and mask_alt.
select
count(*) as rows_checked,
sum(col = col2) as rows_matching,
sum(col != col2) as rows_different
from table
Note the elegant use of sum(condition).
This works because in mysql true is 1 and false is 0. Summing these counts the number of times the condition is true. It's much more elegant than case when condition then 1 else 0 end, which is the SQL equivalent of coding if (condition) return true else return false; instead of simply return condition;.
Assuming you mean you want to count the rows where col1 is or is not equal to col2, you can use an aggregate SUM() coupled with CASE:
SELECT
COUNT(*) AS total,
SUM(CASE WHEN col = col2 THEN 1 ELSE 0 END )AS matching,
SUM(CASE WHEN col <> col2 THEN 1 ELSE 0 END) AS non_matching
FROM table
It may be more efficient to get the total COUNT(*) in a subquery though, and use that value to subtract the matching to get the non-matching, if the above is not performant enough.
SELECT
total,
matching,
total - matching AS non_matching
FROM
(
SELECT
COUNT(*) AS total,
SUM(CASE WHEN col = col2 THEN 1 ELSE 0 END )AS matching
FROM table
) sumtbl

Order by null first, then order by other variable

this is my code for now:
SELECT id, number
FROM Media
WHERE user = 10
ORDER BY id, number
but I want it to look like:
SELECT id, number
FROM Media
WHERE user = 10
ORDER BY while(number IS NULL), id
What I want to do is to have all number that are NULL on the top of the result, but as soon number is not NULL, sort by id
Is that possible?
I use mysql.
what about something like this :
SELECT id, number
FROM Media
WHERE user = 10
ORDER BY (case when number is null then 0 else 1 end), id
If number is NULL, the first order by criteria will be 0 ; else 1
Which means every line will number NULL will come before the others ones
And note that ids will be sorted too, anyway.
You'll get something like this :
number null ; id=1
number null ; id=2
number null ; id=5
number null ; id=8
number not null ; id=3
number not null ; id=4
number not null ; id=7
number not null ; id=10
number not null ; id=12
The ISNULL() function returns 1 if the parameter is null and 0 otherwise.
SELECT id, number
FROM Media
WHERE user = 10
ORDER BY ISNULL(number) DESC, id
Mind you, terrible for performance depending on how many values it needs to order: no index will be used based on the ORDER BY columns.
Union could be used as well.
SELECT id, number
FROM Media
WHERE user = 10 AND number IS NULL
ORDER BY id
UNION
SELECT id, number
FROM Media
WHERE user = 10 AND number IS NOT NULL
ORDER BY id, number;