I want to use BETWEEN in my PHP - MySQL.
Example I have table :
badge_id | balance_type | balance_amount | balance_month
110702 | aa | 250000 | January-2013
110702 | ab | 100000 | January-2013
110702 | aa | 100000 | February-2013
110702 | ab | 90000 | February-2013
110702 | aa | 100000 | March-2013
110702 | ab | 110000 | March-2013
Now I want to SUM just for Balance Month from January-2013 until February-2013.
SELECT balance_type AS balance_type, SUM(balance_amount) AS value_sum
FROM t_balance
WHERE badge_id = '110702' && balance_month BETWEEN 'August-2013'
and 'September-2013'
GROUP BY balance_type
But it will SUM all balance_month.
Any advice?
It's because you have a string column for balance_month. BETWEEN August-2013 and September-2013 is basically BETWEEN A AND S in the alphabet (don't know how to describe it better, lacking english skills here). J for January and F for February is between A and S, so MySQL counts those in. Convert your column to a date
WHERE ... AND STR_TO_DATE(balance_month, '%M-%Y') BETWEEN '2013-08-01'
and '2013-09-30'
But, if I were you I'd get rid of the column and use a real date column. Otherwise an index can not be used on it, when you always have to use a function like str_to_date() on it.
This will work...
SELECT balance_type AS balance_type, SUM(balance_amount) AS value_sum
FROM t_balance
WHERE badge_id = '110702' && STR_TO_DATE(balance_month,'%M-%Y') BETWEEN '2013-08-01'
and '2013-09-30'
GROUP BY balance_type
By an unfortunate twist of fate, all months are between August-2013 and September-2013 -- as you are probably comparing on strings not date.
On MySQL, proper date have the DATE (or one derivable) type and should be formatted as YYYY-MM-DD.
Related
I don't know if this can be done or not. In my MySQL code one of my selects is:
GROUP_CONCAT(timestamp SEPARATOR '~') AS times
What I'd like to do is test the timestamps for being equal at the date/hour/min level and if it is replace the SEPARATOR with a <br>
instead of the tilde. Is there a way to do this in MySQL? If not how would I go about doing it in PHP? The end result needs to be the two (or more) timestamps making a string, which will be used in a table cell. If the date/hour/min are equal then both would be in the same cell. If it helps the timestamps would almost certainly be sequential in the table.
You would typically do that with two levels of aggregation. First aggregate by minute and group_concat with the <br> separator, then aggregate the resulting string again with the ~ separator.
Assuming a table called mytable with a timestamp column called mytimestamp, you would do:
select group_concat(gc0 order by myminute separator '~') gc1
from (
select
date_format(mytimestamp, '%Y-%m-%d %H:%i') myminute,
group_concat(mytimestamp order by mytimestamp separator '<br>') gc0
from mytable
group by myminute
) t
Demo on DB Fiddle:
Sample data:
| mytimestamp |
| :------------------ |
| 2019-01-01 00:00:00 |
| 2019-01-01 00:00:01 |
| 2019-01-01 00:00:10 |
| 2019-01-01 00:01:00 |
| 2019-01-02 14:10:00 |
| 2019-01-02 14:10:30 |
Query results:
| gc1 |
| :------------------------------------------------------------------------------------------------------------------------------- |
| 2019-01-01 00:00:00<br>2019-01-01 00:00:01<br>2019-01-01 00:00:10~2019-01-01 00:01:00~2019-01-02 14:10:00<br>2019-01-02 14:10:30 |
Okay, so I have a table (timetable) in a database (calendar) which if formatted like so:
+----+--------+-----------+-----------+---------+
| id | name | day | startTime | endTime |
+----+--------+-----------+-----------+---------+
| 1 | George | Sunday | 12:00 | 14:00 |
| 2 | Dan | Monday | 13:30 | 15:30 |
| 3 | Jeff | Wednesday | 12:00 | 14:00 |
| 4 | Bill | Monday | 13:45 | 15:45 |
+----+--------+-----------+-----------+---------+
Then I have some PHP as follows:
<?php
$sql = "SELECT * FROM timetable WHERE id IN (1, 2, 3, 4)"
$result = $con->query($sql);
while ($row = mysqli_fetch_assoc($result)) {
$array2[] = $row;
}
echo json_encode($array2, JSON_PRETTY_PRINT);
?>
And that outputs the entire table, as an associated array in JSON format.
I want it to only output the two that clash. There will never be more than two that clash in the database due to the input method, so it only needs to check if there's one clash, and output the JSON for both rows.
I'm not sure where to start. Is it better to do it programatically via PHP, or is there a way to do with with mysql? I was thinking if it's done programatically, maybe two nested for loops and if statements for greater than or less than on the time fields? But seems messy, and I'm thinking there's likely a more clever end elegant solution that I can't think of.
Thank you for any help you can provide.
You can do it with JOIN in SQL like below:-
To find "any overlap", you compare the opposite ends of the timeframe with each other.
SELECT * FROM timetable a
JOIN timetable b
on a.starttime <= b.endtime
and a.endtime >= b.starttime
and a.name != b.name;
the table:
tab_tasks
id|....|date_completed|completed
1 | | 2016-11-05 | Y
2 | | 2016-11-07 | N
3 | | 2016-11-09 | Y
4 | | 2016-12-11 | Y
5 | | 2017-01-15 | Y
6 | | 2017-01-30 | Y
and so on...
I need help in writing sql query by giving current date and get months with counted completed tasks back to max 12 months something like:
month | num_complited
november | 2
december | 1
january | 2
or if it would be easier the instead of letters of the alphabet, month can be numeric 11, 12, 01 in column month.
How can be this accomplished? Is there a need for any php code or can be this done with just sql query? Or should I add extra column to that table, like month?
you should put some date range otherwise for example 11-2016 has 6 count and 11-2017 has 5 so out put will show 11 count data mix-up
SELECT MONTHNAME(date_completed) as month ,
count(completed) as num_complited
from tab_tasks
where completed='Y' and
date_completed between '2016-11-05' and '2017-11-05'
group by MONTHNAME(date_completed)
Try this:
select MONTHNAME(date_completed) as MosName,count(1) as num_completed
from TableName
where completed = 'Y'
GROUP BY MONTHNAME(date_completed);
i have this mysql table with the timetables the train with php,
Type (INT) | time_start | time_stop
1 | 09:31:00 | 09:34:00
1 | 09:43:00 | 09:47:00
1 | 09:55:00 | 09:58:00
1 | 10:07:00 | 10:10:00
1 | 10:33:00 | 10:36:00
1 | 10:45:00 | 10:47:00
1 | 10:57:00 | 11:00:00
1 | 11:12:00 | 11:15:00
1 | 11:35:00 | 11:38:00
(and it goes on..)
- "type" is the timetable type, cus it changes in the winter, summer, etc.
- "type" is INT, and "time_start" and "time_stop" are VARCHAR(8)
I would like to know the most efective way to get the 6 next "train times", acording to the time now.
Imagine, it's now 09:33:10, what I want to obtain is this ones:
1 | 09:43:00 | 09:47:00
1 | 09:55:00 | 09:58:00
1 | 10:07:00 | 10:10:00
1 | 10:33:00 | 10:36:00
1 | 10:45:00 | 10:47:00
1 | 10:57:00 | 11:00:00
If theres any change change i should do in the mysql table, i'm also open to your ideias.
Thanks in advance ;)
Miguel.
You simply could change the VARCHAR type to TIME type, and do a SQL request like
SELECT * FROM <yourtable> WHERE time_start > NOW()
The basic approach is this:
select *
from timetables tt
where tt.time_start > current time
order by tt.time_start
limit 6
There are two challenges with this. The first is midnight. Presumably, if the time is late in the evening, then you want trains in the early morning as well. The second is converting the times to the right format.
select *
from timetable tt
order by (t.time_start > time(now()) desc,
tt.time_start
limit 6
The trick is to move the where condition into the ordering clause. In effect, this starts the ordering at the current time and continues it after midnight. This allows you to select the six with wrapping.
The time() function should be doing the necessary conversion for the comparison.
Just convert your searched time to an int:
$char_time = '09:33:10';
$int_time = (int) str_replace(':','', $char_time);
and then construct your sql like this:
$sql = "SELECT *, CAST(REPLACE(time_start, ',', '') AS INT) as mytime
FROM yourtable WHERE mytime > $int_time
ORDER BY mytime LIMIT 6";
Basically what we do above is just casting your varchar time field to an int type, and using that for comparing, this is a good solution if you can't change your database fields to be of TIME type.
The query will be
SELECT * FROM table_name
WHERE time_start >=time(now())
LIMIT 6
1.emp_ot
table use to define maximum amount of ot hours which employee can do
within specific period
2.daily_attend describe what is actually happen
3.my tables shortened form as follows
mysql> select punchDate,empNO,ot from daily_attend;
+------------+--------+----------+
| punchDate | empNO | ot |
+------------+--------+----------+
| 2012-02-20 | 000123 | 02:00:00 |
| 2012-02-02 | 000123 | 01:00:00 |
| 2012-02-01 | 000126 | 01:00:00 |
| 2012-02-01 | 000123 | 01:00:00 |
+------------+--------+----------+
4 rows in set (0.01 sec)
mysql> select permitId,permitMonth,empNo,dayFrom,dayTO,permitOt from
emp_ot;
+----------+-------------+--------+------------+------------+----------+
| permitId | permitMonth | empNo | dayFrom | dayTO | permitOt |
+----------+-------------+--------+------------+------------+----------+
| 1 | 02 | 000123 | 2012-02-01 | 2012-02-10 | 02:00:00 |
| 2 | 02 | 000123 | 2012-02-20 | 2012-02-25 | 03:00:00 |
| 3 | 02 | 000126 | 2012-02-01 | 2012-01-10 | 02:00:00 |
| 4 | 03 | 000123 | 2012-03-01 | 2012-03-10 | 05:00:00 |
+----------+-------------+--------+------------+------------+----------+
4 rows in set (0.00 sec)
4.here i want to update emp_ot.workedOt to know how many ot hours
had worked under each permitId by employee
ex:
+----------+------------+----------+----------+
| permitId | empNo | workedOt | permitOt |
+----------+----------+----------+----------+
| 1 | 000123 | 02:00:00 | 02:00:00 |
| 2 | 000123 | 02:00:00 | 03:00:00 |
| 3 | 000126 | 01:00:00 | 02:00:00 |
| 4 | 000123 | 00:00:00 | 05:00:00 |
+----------+------------+----------+----------+
5.i'm using mysql event which driven at every day at 00:00:01 that
because table should be automatically update without messing old data
6.my try as follows:
DROP EVENT IF EXISTS make_emp_ot;
DELIMITER |
CREATE EVENT make_emp_ot
ON SCHEDULE EVERY 1 DAY STARTS
TIMESTAMP(CURRENT_DATE,'00:00:01')
DO
BEGIN
INSERT INTO emp_ot( permitMonth,empNo, dayFrom, dayTo, workedOt)
SELECT o.permitId,EXTRACT(MONTH FROM CURRENT_DATE)AS
permitMonth ,o.empNo,'','',(
SELECT ifnull( SEC_TO_TIME(SUM(TIME_TO_SEC(d.ot)))
,'00:00:00')
FROM daily_attend d
WHERE d.punchDate BETWEEN o.dayFrom AND o.dayTo
GROUP BY o.empNo)AS ot
FROM emp_ot o
LEFT JOIN daily_attend d on o.empNo=d.empNo
WHERE o.permitMonth=EXTRACT(MONTH FROM CURRENT_DATE)
ON DUPLICATE KEY UPDATE
workedOt=VALUES(workedOt) ;
END; |
DELIMITER ;
7.i suspect there were bad table joining and actually i don't want
insert part, how to use only update part?
8.please help me to correct these things.Thank you every one.
i'm using mysql event which driven at every day at 00:00:01 that because table should be automatically update without messing old data
Have you considered using triggers?
i suspect there were bad table joining
There are a number of problems with your INSERT ... ON DUPLICATE KEY UPDATE statement:
You specify only five columns in the INSERT part, but the SELECT returns six (I suspect you did not intend to SELECT permitId;
The empty string '' is not a valid date literal for inserting into the dayFrom and dayTo columns (assuming that they are of MySQL's DATE type);
The GROUP BY within your subquery does not make much sense, as the outer query expects only one record: you should restrict its recordset to matches on empNo and remove its GROUP BY clause (all rows will be implicitly grouped by the aggregate function);
Since you have the correlated subquery, joining the tables in the outer query is unnecessary and erroneous (however you could achieve the same results without the correlated subquery by using such a join and then grouping the outer query, which would be more performant);
It isn't clear whether you have appropriate UNIQUE keys defined in order for the ON DUPLICATE KEY UPDATE part to function as expected.
and actually i don't want insert part, how to use only update part?
Use UPDATE instead of INSERT:
UPDATE emp_ot e
SET permitOt := (
SELECT IFNULL(SEC_TO_TIME(SUM(TIME_TO_SEC(d.ot))),0)
FROM daily_attend d
WHERE d.empNo = e.empNo
AND d.punchDate BETWEEN e.dayFrom AND e.dayTO
)
WHERE permitMonth = EXTRACT(MONTH FROM CURRENT_DATE)
See it on sqlfiddle.