SQL select query with multiple conditions issue - mysql

I have a problem with a SQL select query, I can't figure out what it needs to be.
This is what my items table look like:
| id | i_id | last_seen | spot |
----------------------------------------------------
| 1 | ls100 | 2017-03-10 15:30:40 | spot800 |
| 2 | ls100 | 2017-03-10 16:20:15 | spot753 |
| 3 | ls200 | 2017-03-10 16:33:10 | spot800 |
| 4 | ls300 | 2017-03-10 15:30:40 | spot800 |
| 5 | ls300 | 2017-03-10 12:10:30 | spot800 |
| 6 | ls400 | 2017-03-10 10:30:10 | spot800 |
This is what I'm trying to obtain:
| id | i_id | last_seen | spot |
----------------------------------------------------
| 3 | ls200 | 2017-03-10 16:33:10 | spot800 |
| 5 | ls300 | 2017-03-10 12:10:30 | spot800 |
So I need to have the rows where spot= 'spot800', last_seen = MAX(but only if the DateTime is the newest compared to all spots with the samei_id`), and at last the DateTime must be bigger than '2017-03-10 11:00:00'.
This is what I have so far:
SELECT *
FROM items
WHERE spot = 'spot800'
HAVING MAX(`last_seen`)
AND `last_seen` > '2017-03-10 11:00:00'

E.g.:
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,i_id INT NOT NULL
,last_seen DATETIME NOT NULL
,spot INT NOT NULL
);
INSERT INTO my_table VALUES
(1,100,'2017-03-10 15:30:40',800),
(2,100,'2017-03-10 14:20:15',753),
(3,200,'2017-03-10 16:33:10',800),
(4,300,'2017-03-10 15:30:40',800),
(5,300,'2017-03-10 12:10:30',800),
(6,400,'2017-03-10 10:30:10',800);
SELECT [DISTINCT] x.*
FROM my_table x
LEFT
JOIN my_table y
ON y.i_id = x.i_id
AND y.last_seen < x.last_seen
WHERE x.last_seen > '2017-03-10 11:00:00'
AND x.spot = 800
AND y.id IS NULL;
----+------+---------------------+------+
| id | i_id | last_seen | spot |
+----+------+---------------------+------+
| 3 | 200 | 2017-03-10 16:33:10 | 800 |
| 5 | 300 | 2017-03-10 12:10:30 | 800 |
+----+------+---------------------+------+
2 rows in set (0.00 sec)

Use MAX and GROUP BY.
SELECT id, i_id, MAX(last_seen), spot
FROM items
WHERE spot = 'spot800'
AND last_seen > '2017-03-10 11:00:00'
GROUP BY id, i_id, spot

There is several things wrng with your statement.
Firstly, HAVING must be accompanied with a GROUP BY clause, so it's not what you are looking for.
Also, MAX is an aggregate, not a boolean, function. That is, it cannot be used in filters, such as a where clause or a having clause. Also, if it did work, MAX would only return the entry that contains the time as '2017-03-10 16:33:10'. Not what you expected.
Try this instead:
SELECT * FROM items WHERE (spot='spot800' AND last_seen > '2017-03-10 11:00:00');

Related

Recovery the missing hour, minute interval MySQL database

This is part of my table on MySQL database
+----------+---------------------+--------+
| sID | sDatetime | sETX |
+----------+---------------------+--------+
| 16213404 | 2020-04-24 16:00:00 | 497681 |
| 16213398 | 2020-04-20 14:58:56 | 281011 |
+----------+---------------------+--------+
This table count with 14.121.398 records
I realized that in this case more than one hour has passed between the previous and the next row
mysql> SELECT
TIMEDIFF(
'2020-04-20 16:00:00',
'2020-04-20 14:58:56'
);
+------------------------------------------------------------------+
| TIMEDIFF(
'2020-04-20 16:00:00',
'2020-04-20 14:58:56'
) |
+------------------------------------------------------------------+
| 01:01:04 |
+------------------------------------------------------------------+
1 row in set
this is not possible because the data is downloaded maximum from the source every five minutes
in this case is missing the time slot between 3pm and 4pm
I have tried this query without success because the return is all zero
I think because the sID is not consecutive
The code I've tried below
SELECT A.`sID`, A.`sDatetime`, (B.`sDatetime` - A.`sDatetime`) AS timedifference
FROM tbl_2020 A INNER JOIN tbl_2020 B ON B.sID = (A.sID + 1)
ORDER BY A.sID ASC;
how can i find this anomaly in mysql table?
my version of MySQL is 5.5.62-log
the name of column is sDatetime the type is Datetime.
any suggestion, please?
thanks in advance for any help
edit #01
+----------+-----------+---------------------+
| sID | time_diff | sDatetime |
+----------+-----------+---------------------+
| 18389322 | 301 | 2020-05-16 23:53:29 |
| 18390472 | 308 | 2020-05-16 23:48:21 |
| 18389544 | 301 | 2020-05-16 23:43:20 |
| 18388687 | 303 | 2020-05-16 23:38:17 |
| 18388398 | 301 | 2020-05-16 23:33:16 |
| 18390451 | 308 | 2020-05-16 23:28:08 |
| 18388915 | 302 | 2020-05-16 23:23:06 |
| 18388208 | 301 | 2020-05-16 23:18:05 |
| 18390516 | 301 | 2020-05-16 23:13:04 |
| 18389904 | 301 | 2020-05-16 23:08:03 |
+----------+-----------+---------------------+
mysql> SELECT
TIMEDIFF(
'2020-05-16 23:53:29',
'2020-05-16 23:48:21'
) AS td;
+----------+
| td |
+----------+
| 00:05:08 |
+----------+
1 row in set
You should try something like this
SELECT
sID
,TIME_TO_SEC(TIMEDIFF(#date,sDatetime)) time_diff
,#date := sDatetime
,sETX
FROM(
SELECT * FROM table1
ORDER BY sDatetime DESC) s1,(SELECT #date :=(SELECT MAX(sDatetime) FROM table1)) s2
HAVING time_diff > 300
First you order the table by time, then you get the time difference between two consecutive rows and check if they are bigger than 5 minutes
see example here https://www.db-fiddle.com/f/2yKt6d5RWngXVYJKPGZL6m/8
Comparing current row to previous works
drop table if exists t;
create table t
(sID int, sDatetime datetime, sETX int);
insert into t values
( 16213404 , '2020-04-24 16:00:00' , 497681),
( 16213398 , '2020-04-20 14:58:56' , 281011);
select sid,sdatetime,(select sdatetime from t t1 where t1.sid < t.sid order by t1.sid desc limit 1) prevdt,
time_to_sec(sdatetime) - time_to_sec((select sdatetime from t t1 where t1.sid < t.sid order by t1.sid desc limit 1)) diff
from t
where time_to_sec(sdatetime) - time_to_sec((select sdatetime from t t1 where t1.sid < t.sid order by t1.sid desc limit 1)) > 300;
+----------+---------------------+---------------------+------+
| sid | sdatetime | prevdt | diff |
+----------+---------------------+---------------------+------+
| 16213404 | 2020-04-24 16:00:00 | 2020-04-20 14:58:56 | 3664 |
+----------+---------------------+---------------------+------+
1 row in set (0.002 sec)
If this is too slow add your table definition so that we can see the indexes you have.

Mysql select query with condition

I have a Mysql table with the following data.
|ID | Date | BillNumber|BillMonth | Amount | Name |AccNum |
| 2 |2015-09-25| 454345 | 092015 | 135.00 |Andrew Good| 735976|
| 3 |2015-09-26| 356282 | 092015 | 142.00 |Peter Pan | 123489|
| 4 |2015-08-11| 312738 | 082015 | 162.00 |Andrew Good| 735976|
| 5 |2015-07-12| 287628 | 072015 | 220.67 |Andrew Good| 735976|
| 6 |2015-06-12| 100756 | 062015 | 556.34 |Andrew Good| 735976|
What I wanted to achieve is to retrieve the data of Andrew Good with AccNum 735976 for the BillMonth of 092015, provided that the user can entry any of his BillNumber(past/current).
If the reason that that row is of interest is because it is the latest of his rows, try:
select *
from tbl t
where name = ( select name
from tbl
where billnumber = 100756 -- can be any of his
)
and date = ( select max(date)
from tbl x
where x.name = t.name
)
(the billnumber can be any of his)

Query to get values of one table which are not there in string column of another table, also less than a particular datetime value

I have a two tables :
mysql> select * from quizquestionbank;
| ID | QuestionFilePath | CorrectAnswer | EndDate |
--------------------------------------------------------------
| 1 | p.wav | 1 |2014-05-12 12:00:00 |
| 2 | q.wav | 2 |2014-05-12 12:00:00 |
| 3 | a.wav | 3 |2014-05-12 12:00:00 |
| 4 | b.wav | 1 |2014-05-12 12:00:00 |
| 5 | m.wav | 3 |2014-05-12 12:00:00 |
Second table is :
mysql> select * from quizuserdetails;
| ID | MSISDN | QuestionIdDetails | AnswerRecord |
--------------------------------------------------
| 1 | 235346 | 1,3,4,5 | S,F,S,F |
| 2 | 564574 | 4,5,67,88 | F,S,F,s |
| 3 | 500574 | 5,55,66,44,2 | F,F,F,F |
I want to get the IDs from table 1 which :
1. are not there in QuestionIdDetails column of second table and
2. less than current date and time.
Following Query gives me records required for first point:
Select qb.ID,qb.EndDate
from quizquestionbank qb
left join quizuserdetails qd
on find_in_set(qb.id, QuestionIdDetails) > 0
and msisdn = '235346'
where qd.id is null
But for second requirement following query gives error :
Select *
from predictionfootball
where '2014-05-10 00:00:00' <
(Select qb.ID,qb.EndDate
from quizquestionbank qb
left join quizuserdetails qd
on find_in_set(qb.id, QuestionIdDetails) > 0
and msisdn = '235346'
where qd.id is null)
Please tell me the way to do it.
Try that:
Select qb.ID,qb.EndDate
from quizquestionbank qb
left join quizuserdetails qd
on find_in_set(qb.id, QuestionIdDetails) > 0
and msisdn = '235346'
where qd.id is null
AND qb.EndDate < '2014-05-10 00:00:00' ------> added this line

Update the next row of the target row in MySQL

Suppose I have a table that tracks if a payment is missed like this:
+----+---------+------------+------------+---------+--------+
| id | loan_id | amount_due | due_at | paid_at | missed |
+----+---------+------------+------------+---------+--------+
| 1 | 1 | 100 | 2013-08-17 | NULL | NULL |
| 5 | 1 | 100 | 2013-09-17 | NULL | NULL |
| 7 | 1 | 100 | 2013-10-17 | NULL | NULL |
+----+---------+------------+------------+---------+--------+
And, for example, I ran a query that checks if a payment is missed like this:
UPDATE loan_payments
SET missed = 1
WHERE DATEDIFF(NOW(), due_at) >= 10
AND paid_at IS NULL
Then suppose that the row with id = 1 gets affected. I want the amount_due of row with id = 1 be added to the amount_due of the next row so the table would look like this:
+----+---------+------------+------------+---------+--------+
| id | loan_id | amount_due | due_at | paid_at | missed |
+----+---------+------------+------------+---------+--------+
| 1 | 1 | 100 | 2013-08-17 | NULL | 1 |
| 5 | 1 | 200 | 2013-09-17 | NULL | NULL |
| 7 | 1 | 100 | 2013-10-17 | NULL | NULL |
+----+---------+------------+------------+---------+--------+
Any advice on how to do it?
Thanks
Take a look at this :
SQL Fiddle
MySQL 5.5.32 Schema Setup:
CREATE TABLE loan_payments
(`id` int, `loan_id` int, `amount_due` int,
`due_at` varchar(10), `paid_at` varchar(4), `missed` varchar(4))
;
INSERT INTO loan_payments
(`id`, `loan_id`, `amount_due`, `due_at`, `paid_at`, `missed`)
VALUES
(1, 1, 100, '2013-09-17', NULL, NULL),
(3, 2, 100, '2013-09-17', NULL, NULL),
(5, 1, 100, '2013-10-17', NULL, NULL),
(7, 1, 100, '2013-11-17', NULL, NULL)
;
UPDATE loan_payments AS l
LEFT OUTER JOIN (SELECT loan_id, MIN(ID) AS ID
FROM loan_payments
WHERE DATEDIFF(NOW(), due_at) < 0
GROUP BY loan_id) AS l2 ON l.loan_id = l2.loan_id
LEFT OUTER JOIN loan_payments AS l3 ON l2.id = l3.id
SET l.missed = 1, l3.amount_due = l3.amount_due + l.amount_due
WHERE DATEDIFF(NOW(), l.due_at) >= 10
AND l.paid_at IS NULL
;
Query 1:
SELECT *
FROM loan_payments
Results:
| ID | LOAN_ID | AMOUNT_DUE | DUE_AT | PAID_AT | MISSED |
|----|---------|------------|------------|---------|--------|
| 1 | 1 | 100 | 2013-09-17 | (null) | 1 |
| 3 | 2 | 100 | 2013-09-17 | (null) | 1 |
| 5 | 1 | 200 | 2013-10-17 | (null) | (null) |
| 7 | 1 | 100 | 2013-11-17 | (null) | (null) |
Unfortunately I don't have time at the moment to write out full-blown SQL, but here's the psuedocode I think you need to implement:
select all DISTINCT loan_id from table loan_payments
for each loan_id:
set missed = 1 for all outstanding payments for loan_id (as determined by date)
select the sum of all outstanding payments for loan_id
add this sum to the amount_due for the loan's next due date after today
Refer to this for how to loop using pure MySQL: http://dev.mysql.com/doc/refman/5.7/en/cursors.html
I fixed my own problem by adding a missed_at field. I put the current timestamp ($now) in a variable before I update the first row to missed = 1 and missed_at = $now then I ran this query to update the next row's amount_due:
UPDATE loan_payments lp1 JOIN loan_payments lp2 ON lp1.due_at > lp2.due_at
SET lp1.amount_due = lp2.amount_due + lp1.amount_due
WHERE lp2.missed_at = $now AND DATEDIFF(lp1.due_at, lp2.due_at) <= DAYOFMONTH(LAST_DAY(lp1.due_at))
I wish I could use just use LIMIT 1 to that query but it turns out that it's not possible for an UPDATE query with a JOIN.
So all in all, I used two queries to achieve what I want. It did the trick.
Please advise if you have better solutions.
Thanks!

How to calculated multiple moving average in MySQL

Using table below, How would get a column for 5 period moving average, 10 period moving average, 5 period exponential moving average.
+--------+------------+
| price | data_date |
+--------+------------+
| 122.29 | 2009-10-08 |
| 122.78 | 2009-10-07 |
| 121.35 | 2009-10-06 |
| 119.75 | 2009-10-05 |
| 119.02 | 2009-10-02 |
| 117.90 | 2009-10-01 |
| 119.61 | 2009-09-30 |
| 118.81 | 2009-09-29 |
| 119.33 | 2009-09-28 |
| 121.08 | 2009-09-25 |
+--------+------------+
The 5-row moving average in your example won't work. The LIMIT operator applies to the return set, not the rows being considered for the aggregates, so changing it makes no difference to the aggregate values.
SELECT AVG(a.price) FROM (SELECT price FROM t1 WHERE data_date <= ? ORDER BY data_date DESC LIMIT 5) AS a;
Replace ? with the date whose MA you need.
SELECT t1.data_date,
( SELECT SUM(t2.price) / COUNT(t2.price) as MA5 FROM mytable AS t2 WHERE DATEDIFF(t1.data_date, t2.data_date) BETWEEN 0 AND 6 )
FROM mytable AS t1 ORDER BY t1.data_date;
Change 6 to 13 for 10-day MA