Order by null first, then order by other variable - mysql

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;

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.

Get the earliest time if rows are more than 1

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))

Why does the total from my query results not add up?

I have three queries that get stats from the database, but the total does not add up correctly for my results. If I do the math myself this is what I get: // 440728 / 1128 = 390.72
However, the following is what is returned by my queries:
SELECT * FROM facebook_accts
WHERE user_id IN (SELECT id FROM `user_accts` WHERE owner_id = '121')
// returns 1128
SELECT sum(friend_count) FROM facebook_accts
WHERE user_id IN
(SELECT id FROM `user_accts` WHERE owner_id = '121')
// returns 440728
SELECT avg(friend_count) FROM facebook_accts
WHERE user_id IN
(SELECT id FROM `user_accts` WHERE owner_id = '121')
// returns 392.11 (number formatted to two decimal places by php)
this may be happening because of column friend_count having some NULL values because SUM and AVG sunctions ignore NULL values. see here.
I guess the 1128 rows contain NULL values (which AVG and SUM ignore).

how can I tell if the last x rows of 'state' = 1

I need help with a SQL query.
I have a table with a 'state' column. 0 means closed and 1 means opened.
Different users want to be notified after there have been x consecutive 1 events.
With an SQL query, how can I tell if the last x rows of 'state' = 1?
If, for example, you want to check if the last 5 consecutive rows have a state equals to 1, then here's you could probably do it :
SELECT IF(SUM(x.state) = 5, 1, 0) AS is_consecutive
FROM (
SELECT state
FROM table
WHERE Processor = 3
ORDER BY Status_datetime DESC
LIMIT 5
) as x
If is_consecutive = 1, then, yes, there is 5 last consecutive rows with state = 1.
Edit : As suggested in the comments, you'll have to use ORDER BY in your query, to get the last nth rows.
And for more accuracy, since you have a timestamp column, you should use Status_datetime to order the rows.
You should be able to use something like this (replace the number in the HAVING with the value of x you want to check for):
SELECT Processor, OpenCount FROM
(
SELECT TOP 10 Processor, DateTime, Sum(Status) AS OpenCount
FROM YourTable
WHERE Processor = 3
ORDER BY DateTime DESC
) HAVING OpenCount >= 10