Count Number of rows with negative integers in mysql - mysql

i have a timestamp column in my DB and i want to sum the number of rows that are passed due, let me show you the query for that!
SELECT TIMESTAMPDIFF(MINUTE, `Opened`, NOW()) as PastDue FROM `Task`
not this query returns the perfect result and return all rows where past due is negative and others are positive
now i want to count the number of negative rows so i did
SELECT COUNT(TIMESTAMPDIFF(MINUTE, `Opened`, NOW())) < 0 as PastDue FROM `Task`
it currently returns 0 now there are two rows with negative result so it should return two but it always returns 0 , can anyone point out what i am missing?

COUNT(TIMESTAMPDIFF(MINUTE, `Opened`, NOW())) < 0
is a boolean expression (checking whether the COUNT is less than 0), which will always return 0 (false) since a COUNT must be at least 0. What you can do instead is SUM the results of the test (since MySQL treats booleans as 0 or 1 in a numeric context):
SELECT SUM(TIMESTAMPDIFF(MINUTE, `Opened`, NOW()) < 0) as PastDue FROM `Task`
Note that you can simplify this query to just compare Opened with NOW(), either in the SUM:
SELECT SUM(`Opened` > NOW()) AS PastDue
FROM `Task`
or using COUNT(*) with a WHERE clause:
SELECT COUNT(*) AS PastDue
FROM `Task`
WHERE `Opened` > NOW()
Note that based on the wording of your question, you probably want to change the condition from
`Opened` > NOW()
to
`Opened` < NOW()

Related

Is it possible to make a SQL statement, based on a single column?

I'm struggling to write down an SQL statement for a query.
Basically, I want to select a record, based on a field, if this field is bigger than 0, then it should check if 1 hour is passed from a datetime field, if the field is lower or equal to 0 then it should ignore that check and just select it
In C# it would be something like this:
if (columnA > 0)
{
//select if (columnB < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 1 HOUR)))
//if it's not match, move on to next record
} else {
//just select it
}
So, in SQL what would be? Something like this:
SELECT field1, field2
FROM table
WHERE id = 1
AND intLv < fieldLv
AND IF (limitedLogin > 0) { lastLogin < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL time HOUR) AND logins < totLogins }
ORDER BY id DESC LIMIT 1
I'm not expert on SQL/MySQL statements, so I don't know if that is entirely possible. Could someone enlighten me?
Basically, I want to select a record, based on a field, if this field is bigger than 0, then it should check if 1 hour is passed from a datetime field, if the field is lower or equal to 0 then it should ignore that check and just select it
You seem to be describing logic like this:
where columnA < 0 or
columnB < now() - interval 1 hour;
Note: This assumes that = 0 is the same as > 0.
The first condition returns all rows where columnA < 0. The second returns rows where column b is more than one hour ago.

MySql query is taking more than 60s to execute. How to improve performance

I have written a query to select all rows where value of a column 'gvA' in previous row is 0 and non-zero in current row. But my issue is this query takes too long to execute.
My table has 40000 rows and query takes about 60-65 seconds which is too much for a query. How can I improve query for better performance.Following is my query
SELECT device_no,datetime
FROM (
SELECT
gvA,
(SELECT e2.gvA
FROM tyn_records e2
WHERE e2.tyn_id < e1.tyn_id
ORDER BY tyn_id DESC LIMIT 1) as previous_value,
datetime,
device_no
FROM tyn_records e1
WHERE gvA > 0 AND DATE(datetime) = CURDATE() - INTERVAL 2 DAY
) selected
WHERE selected.previous_value = 0
Following are my tables
Devices:
tyn_records:
I would do two things:
I would rephrase the query a bit, specifically to remove the DATE() function in the left side of the filtering condition.
select
device_no,
datetime
from (
select
gva,
lag(gva) over(order by tyn_id) as previous_value,
datetime,
device_no
from tyn_records
where gva > 0
and datetime between curdate() - interval 2 day
and curdate() - interval 1 day
) x
where previous_value = 0
With the function on the left side of the predicate removed, you can create an index suitable to optimize the query:
create index ix1 on tyn_records (datetime, gva);
As a side note, the way you compute previous_value may not be deterministic, and could produce different results each time you run the query. This may happen if the column tyn_id is non unique.

How to use cases on order by in Mysql?

If t_date(column_name) is Today's date then
select * from `schedules`
ORDER BY available_seats <= 0 , STR_TO_DATE(departure_time,'%h:%i%p');
Else
select * from `schedules`
ORDER BY (available_seats <= 0 && (STR_TO_DATE(departure_time,'%h:%i%p') >= TIME(NOW()))), (STR_TO_DATE(departure_time,'%h:%i%p') <= TIME(NOW())), STR_TO_DATE(departure_time,'%h:%i%p');
END
Query 1 is for t_date = DATE(now())
Query 2 is for t_date != DATE(now())
How can i make it in a single query with condition on order by??
You can use CASE like below
SELECT *
FROM `schedules`
ORDER BY
available_seats <= 0 ,
CASE WHEN t_date <> CURRENT_DATE() AND (available_seats <= 0 && (STR_TO_DATE(departure_time,'%h:%i%p') >= TIME(NOW())))
THEN
(STR_TO_DATE(departure_time,'%h:%i%p') <= TIME(NOW()))
WHEN t_date = CURRENT_DATE()
THEN STR_TO_DATE(departure_time,'%h:%i%p')
ELSE STR_TO_DATE(departure_time,'%h:%i%p') END,
STR_TO_DATE(departure_time,'%h:%i%p')
In English, what are you actually trying to get your order by and maybe adjust your question for clarification...
However, I think you might want all "available_seats" values less or equal to zero FIRST, THEN based on the date from today. If that is the case, you may want something like..
order by
case when available_seats <= 0 then 1 else 2 end,
STR_TO_DATE(departure_time,'%h:%i%p')
But it should all be possible in a simple single query, but there is no context to what the seats, dates are for and what you want and why... Are you looking for something like "Sold-out" events sorted to top of list, then based on date of event with closest coming event listed first?
The case/when I have above basically puts any returned records that have available seats <= 0 in the first order sequence regardless of actual 0 or negative value... Then, anything else, if 1 seat or 1000 seats left are sorted after. The SECOND part of the order by is just on the date_time field itself. Since the order by is regardless of the "formatted" column that might be retrieved in the field list, I am just ordering by the date/based conversion as you had.

MySQL query to return number 'zero' if no results

When selecting a DATE and that date does not exist in my table it currently will return an empty result set. How can I be able to return the number zero for those empty result sets instead?:
SELECT SUM(TOTAL), SUM(5STAR), STORE, DATE
FROM `table` WHERE DATE >= '2012-02-24' GROUP BY TOTAL
MySQL returned an empty result set (i.e. zero rows)
I want to instead return the results of the SUM(TOTAL) and SUM(5STAR) (if zero rows) as the number zero (0).
FULL TABLE STRUCTURE:
ID = Primary
DATE = UNIQUE (date)
STORE
5STAR
4STAR
3STAR
2STAR
1STAR
TOTAL
FROM = UNIQUE
Try COALESCE
SELECT COALESCE(SUM(TOTAL),0), COALESCE(SUM(5STAR),0), STORE, DATE
FROM `table` WHERE DATE >= '2012-02-24' GROUP BY TOTAL
TRY
SELECT
IFNULL(SUM(TOTAL), 0) AS total,
IFNULL(SUM(5STAR), 0) AS FiveStar,
STORE,
DATE
FROM `table`
WHERE DATE >= '2012-02-24'
GROUP BY TOTAL
Reference
I think it would be easier to handle the empty result set on the PHP side (count the returned rows). If you want to handle it in the database, you should create a stored procedure.
DELIMITER $$
CREATE PROCEDURE `mc`.`new_routine` (IN DT DATETIME)
BEGIN
IF EXISTS (SELECT 1 FROM `table` WHERE DATE >= #DT)
THEN
SELECT SUM(TOTAL) AS SumTotal, SUM(5STAR) AS Sum5Star, STORE, `DATE`
FROM `table`
WHERE DATE >= #DT
GROUP BY TOTAL;
ELSE
SELECT 0 AS SumTotal, 0 AS Sum5Star, NULL AS STORE, NULL AS `DATE`;
END IF;
END

MySQL: combining 2 queries (one empty) using UNION ALL results in error "1048 - Column cannot be NULL"

I need to return two different results in a single query. When I run them independently, the first returns no rows (that's fine) and the second returns some rows (also fine). When I UNION ALL them, I get 1048 - Column "Date" cannot be null.
I need resulting rows of Date, PW, errors which I will feed a graph to show me what's going on in the system at the points in time specified by Date. In both tables, Date is of the format DateTime and must never be NULL.
SELECT `Date`, COUNT(`ID`) AS `PW`, 0 AS `errors`
FROM `systemlogins`
WHERE `Result` = 'PasswordFailure' AND `Date` >= DATE_SUB(NOW(), INTERVAL 1 DAY)
UNION ALL
SELECT `Date`, 0 AS `PW`, COUNT(`ID`) AS `errors`
FROM `systemerrors`
WHERE `Date` >= DATE_SUB(NOW(), INTERVAL 1 DAY)
GROUP BY ( 4 * HOUR( `Date` ) + FLOOR( MINUTE( `Date` )/15)) --i.e. full 1/4s of hour
ORDER BY ( 4 * HOUR( `Date` ) + FLOOR( MINUTE( `Date` )/15))
I have read that MySQL might ignore tables' NOT NULL conditions in UNIONs, causing that error. I have indeed removed the "NOT NULL" restriction on the tables and, tada, it works. Now, those restrictions have been put there for a reason and I would like to keep them while running the aforementioned query - is there any way?
Edit:
Order is the villain - removing it returns a correct result, albeit with one empty row where Date is NULL. For my purposes, I need to order the results by Date somehow.
Why are you selecting the Date column? Since you are using a aggregate function COUNT, but there is no GROUP BY clause in any of the selects, seems to me that you do not care about the Date column.
Try adding a GROUP BY clause, or removing the Date column from the select.