Why i get Null values in my second counter using case statement - mysql

The first case statement i got the correct result but in the second one
Why i got an NULL result Where my second case statement the counter = 2
this is the result i have an image
Query Result that i got Null data in second statement when i grouped by on my date
SELECT DISTINCT date,log,
CASE
WHEN note = 'HOLIDAY' AND counter = 1
THEN 'HOLIDAY'
END note1,
CASE
WHEN note = 'HOLIDAY' AND counter = 2
THEN 'HOLIDAY'
END note2,
FROM timesheet
WHERE timesheet.empid='40' AND date <= CURDATE() AND YEAR(date)= YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
GROUP BY date
ORDER BY date DESC;

You're using GROUP BY wrong. The rule is that each column in your SELECT clause is either also in your GROUP BY clause or an aggregate function (like count, min, max, avg) must be applied to it.
When you don't follow this rule, a random row for each group is displayed. In your case, when you really have data with note = 'HOLIDAY' AND counter = 2, the rows for the group might look like this
NULL
HOLIDAY
NULL
NULL
but after collapsing (when it's outputted by the select), just the first row is displayed, therefore the NULL value.
Try it like this:
SELECT date,
MIN(log), /*or maybe you want to group by this column, too? */
MAX(CASE
WHEN note = 'HOLIDAY' AND counter = 1
THEN 'HOLIDAY'
END) note1,
MAX(CASE
WHEN note = 'HOLIDAY' AND counter = 2
THEN 'HOLIDAY'
END) note2,
FROM timesheet
WHERE timesheet.empid='40' AND date <= CURDATE() AND YEAR(date)= YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
GROUP BY date
ORDER BY date DESC;
Also note, that I removed the DISTINCT. Your GROUP BY already does that.

Related

Mysql 'greater than(>)' query always returns 0

I am working with a query where I want to display number of upcoming dates. The following query returns 0 even though there are dates greater than current date. Please help me to solve this problem.
SELECT (case when b.booked_date > cast(now() as date) then sum(1) else sum(0) end) as upcoming_booked_facilities
from svk_apt_book_facilities b
where b.customer_id = 1
and b.association_id = 1
and b.is_active = 1
group by b.facility_id
You need to sum a CASE expression to do conditional aggregation:
SELECT
facility_id,
SUM(CASE WHEN booked_date > CURDATE() THEN 1 ELSE 0 END) AS upcoming_booked_facilities
FROM svk_apt_book_facilities
WHERE
customer_id = 1 AND
association_id = 1 AND
is_active = 1
GROUP BY
facility_id;
You were trying to use the sum as the predicate of the CASE expression, which is probably not what you want. Note that I am also selecting the facility_id, since you are grouping by that column. If you instead want a conditional sum over the entire table, then don't select or group by facility.

Multiple COUNT() conditions for values on either side of a range

I currently have a query that finds all rows (with status=0) that have occurred before now:
SELECT id, COUNT(1) FROM tbl WHERE status = 0 AND date < UNIX_TIMESTAMP() GROUP BY id;
However, now I'd also like to be able to retrieve the values on the other side of this--i.e., I want to get all dates available after and before now, as two distinct values.
Is there any way to optimize this besides simply running two separate queries?
SELECT id
, SUM(date < UNIX_TIMESTAMP()) AS BeforeNow
, SUM(date > UNIX_TIMESTAMP()) AS AfterNow
FROM tbl
WHERE status = 0
GROUP BY id;
date < UNIX_TIMESTAMP() is a boolean expression, which equates to 1 or 0. The SUM of the expression is equal to the amount of times it was true, or its count.
You can do a conditional count.
SELECT id,
COUNT(CASE WHEN date < UNIX_TIMESTAMP() THEN 1 ELSE null END ) ,
COUNT(CASE WHEN date > UNIX_TIMESTAMP() THEN 1 ELSE null END )
FROM tbl GROUP BY id

Totalling query in last row

This query will return a list of engineer names with test results for what they have tested in the last hour, what is faulty, what's is working and the total for each engineer.
I want to be able to add a row at the bottom which will total these amounts but am struggling, any one have any suggestions?
select distinct qcheck.checkby,
ifnull(fully,0) as fully,
ifnull(faulty,0) as faulty,
ifnull(lasthour,0) as lasthour,
ifnull(total,0) as total
from qcheck
left join (
select count(*) AS fully,
checkby,
qcheck.id
from qcheck
where result = 'fully tested & working'
and date(finishdate) = CURDATE()
group by checkby) AS fw
on fw.checkby=qcheck.checkby
left join (
select count(*) AS faulty,
checkby,
qcheck.id
from qcheck
where result = 'faulty'
and date(finishdate) = CURDATE()
group by checkby) AS ff
on ff.checkby=qcheck.checkby
left join (
select count(*) AS Lasthour,
checkby,
qcheck.id from qcheck
where finishdate >= now() - interval 1 hour
group by checkby) AS lh
on lh.checkby=qcheck.checkby
left join (
select count(*) AS total,
checkby,
qcheck.id from qcheck
where date(finishdate) = CURDATE()
group by checkby) AS total
on total.checkby=qcheck.checkby
where date(finishdate) = CURDATE()
and qcheck.checkby not like 'michael'
and qcheck.checkby not like 'chaz'
group by qcheck.checkby
order by total desc
First of all, you don't need the sub queries, you can instead do a count on a condition.
The with rollup modifier can be added to the group by clause to include the grand total. The order by cannot be used in the same query then, but can be applied in an outer query.
Furthermore, with the use of coalesce you can replace the null value for that total row with the label of your choice.
Finally, to still sort the total row at the end, you could add an is null expression in the order by clause, which will evaluate to false or true. The latter is ordered last.
select coalesce(checkby, 'Total') as checkby_or_total,
fully,
faulty,
lasthour,
total
from (
select qcheck.checkby,
count(case result when 'fully tested & working' then 1 end) as fully,
count(case result when 'faulty' then 1 end) as faulty,
count(case when finishdate >= now()-interval 1 hour then 1 end) as lasthour,
count(*) as total
from qcheck
where date(finishdate) = CURDATE()
and qcheck.checkby not like 'michael'
and qcheck.checkby not like 'chaz'
group by qcheck.checkby with rollup
) as main
order by checkby is null,
total desc

How to add new column in select statement

i want to add new column in my select statement
SELECT name,line,style,operation,
7to8am,8to9am,9to10am,10to11am,11to12am,
1to2pm,2to3pm,3to4pm,4to5pm,5to6pm,6to7pm,7to8pm,8to9pm,9to10pm,10to11pm,11to12pm,
sum(7to8am+8to9am+9to10am+10to11am+11to12am+1to2pm
+2to3pm+3to4pm+4to5pm+5to6pm+6to7pm+7to8pm+
8to9pm+9to10pm+10to11pm+11to12pm) as DailyTotal,id from new_hourly GROUP By line
i want to add a new column that will show sum of DailyTotal that the day is today
This is my sql backup file http://www.uploadmb.com/dw.php?id=1446536983
Please help me! thank you so much!
So you want one additional columns that adds only lines where datee equals current date?
I'd go for case-when expression in this case:
coalesce(
sum(
case
when datee = CURDATE()
then 7to8am+8to9am+9to10am+10to11am+11to12am+1to2pm+2to3pm+3to4pm+4to5pm+5to6pm+6to7pm+7to8pm+8to9pm+9to10pm+10to11pm+11to12pm
else null
end
)
,0) as TodaysTotal
That's summing up only those rows where column datee is curdate() and returning 0 if no rows at all are present for today.
Full SQL:
SELECT name,line,style,operation,
7to8am,8to9am,9to10am,10to11am,11to12am,
1to2pm,2to3pm,3to4pm,4to5pm,5to6pm,6to7pm,7to8pm,8to9pm,9to10pm,10to11pm,11to12pm,
sum(7to8am+8to9am+9to10am+10to11am+11to12am+1to2pm
+2to3pm+3to4pm+4to5pm+5to6pm+6to7pm+7to8pm+
8to9pm+9to10pm+10to11pm+11to12pm) as DailyTotal,
coalesce(
sum(
case
when datee = CURDATE()
then 7to8am+8to9am+9to10am+10to11am+11to12am+1to2pm+2to3pm+3to4pm+4to5pm+5to6pm+6to7pm+7to8pm+8to9pm+9to10pm+10to11pm+11to12pm
else null
end
)
,0) as TodaysTotal
,id from new_hourly GROUP By line

How to categorize customer through MYSQL query?

I am finding difficulty in writing mysql query to categorize my customers. I am categorizing customers based on number of hits on my website.like
New customer with one hits.
New customer with multiple hits.
Old customer
My Log table schema is as follows
Unique customer ID, Current Date, Subscribed, Hits Count
To categorize customer how can I compare current date customer logs with all the previous date logs through single query
It's not clear from your description, is customer_id unique?
Or is it the tuple (customer_id,current_date,subscribed,hits_count) that is unique?
If customer_id is unique, then something like this will return the specified result:
SELECT t.customer_id
, CASE
WHEN t.hits_count = 1 AND t.current_date = DATE(NOW())
THEN 'New customer with one hits.'
WHEN t.hits_count > 1 AND t.current_date = DATE(NOW())
THEN 'New customer with multiple hits.'
ELSE 'Old customer'
END AS category
FROM mytable t
If customer_id is not unique, then one way (but not the most efficient way) to get the specified result:
SELECT t.customer_id
, CASE
WHEN t.total_hits_count = 1 AND t.min_current_date = DATE(NOW())
THEN 'New customer with one hits.'
WHEN t.total_hits_count > 1 AND t.min_current_date = DATE(NOW())
THEN 'New customer with multiple hits.'
ELSE 'Old customer'
END AS category
FROM ( SELECT h.customer_id
, MIN(h.current_date) AS min_current_date
, SUM(h.hits_count) AS total_hits_count
FROM mytable h
GROUP BY h.customer_id
) t
The inline view aliased as t gets us unique values for customer_id, along with the earliest current_date, and the total of the hits_count. (You can run just the query inside the parens to verify it's returning the desired result.) The outer query is identical to the first query, with just some renamed columns.
The inline view isn't necessary, you could get an equivalent result (more efficiently) with something like this:
SELECT t.customer_id
, CASE
WHEN SUM(t.hits_count) = 1 AND MIN(t.current_date) = DATE(NOW())
THEN 'New customer with one hits.'
WHEN SUM(t.hits_count) > 1 AND MIN(t.current_date) = DATE(NOW())
THEN 'New customer with multiple hits.'
ELSE 'Old customer'
END AS category
FROM mytable t
GROUP BY t.customer_id
NOTE There's some corner cases that will cause customer_id to be categorized as 'Old customer', such as SUM(t.hits_count) < 1, or t.current_date IS NULL, etc.
To specifically test for a row with a current_date before today's date, make a specific test for that in the CASE expression:
SELECT t.customer_id
, CASE
WHEN SUM(t.hits_count) = 1 AND MIN(t.current_date) = DATE(NOW())
THEN 'New customer with one hits.'
WHEN SUM(t.hits_count) > 1 AND MIN(t.current_date) = DATE(NOW())
THEN 'New customer with multiple hits.'
WHEN MIN(t.current_date) < DATE(NOW())
THEN 'Old customer'
ELSE 'Some other category'
END AS category
FROM mytable t
GROUP BY t.customer_id
NOTE
I assumed that the current_date column was of type DATE, and not DATETIME or TIMESTAMP. If that column also includes a time component which is not equal to midnight 00:00:00, then the equality comparison to DATE(NOW()) is not going to return TRUE whenever that time component is not midnight.
In that case, we'd prefer to check a range of datetime values, replacing
... AND t.current_date = DATE(NOW())
with something like this:
... AND t.current_date >= DATE(NOW()) AND t.current_date < DATE(NOW()) + INTERVAL 1 DAY