PHP MySQL query- group by date in datetime field - php

I've been searching and I know there are similar questions, but none of them seems to answer this particular question.
I am trying to get a count of the total number of days an employee has worked on a given schedule. To do this, I am counting the total number of rows the employee appears on the "schedules" table. Only we run into a problem if the employee is scheduled twice on the same day.
To solve this, I want to count total number of rows and sort by DATE in a DATETIME field.
Current query:
$days = mysql_query("SELECT emp_id FROM schedules
WHERE sch_id = '$sch_id'
AND emp_id = '$emp_data[emp_id]'");
$tot_days = mysql_num_rows($days);
I would like to change it to:
$days = mysql_query("SELECT emp_id FROM schedules
WHERE sch_id = '$sch_id'
AND emp_id = '$emp_data[emp_id]'
GROUP BY start_date");
// "start_date" is a datetime field. Need to sort by date only YYYY-MM-DD
$tot_days = mysql_num_rows($days);
Any thoughts?

If your start_date column is a MySQL datetime type, you could use the following:
$days = mysql_query("SELECT start_date, count(*) FROM schedules
WHERE sch_id = '$sch_id'
AND emp_id = '$emp_data[emp_id]'
GROUP BY DATE(start_date)
HAVING count(*) > 1
ORDER BY DATE(start_date)");
The DATE function "Extracts the date part of the date or datetime expression"
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date
This will give you only those rows where the emp_id being considered is used more than once in a given date. Remove the HAVING line if you want to see all.

Related

SQL query date range saved in 2 columns

I have a table (Hire Rates) which contains multiple records. I'm trying to find records based on a date query but cannot get it to work correctly.
Essentially I am looking for records that contain a date between two dates. If my query date is "2021-08-15", it should return the third row (3000) as the query date falls between the two dates.
It is mostly working for me, except if the query date is equal to the start date or end date - in that case it doesn't return any result.
Table
startDate
endDate
hireRate
2021-01-01
2021-03-05
2350
2021-03-06
2021-04-08
2890
2021-04-09
2021-09-15
3000
Query
$sql = "SELECT rate, currencyID FROM hire_rates WHERE status = '1' AND NOT (startDate >= '$queryDate' OR endDate <= '$queryDate')
Try adding 'between' condition.
Like
select rate, currencyId from hire_rates where states =1 and not (cast($queryDate as DATE) between cast(startDate As DATE) and cast(endDate AS DATE) )
You would pass in the date you care about as a parameter. Then you can use between (based on your description of the logic):
SELECT rate, currencyID
FROM hire_rates
WHERE status = 1 AND
? BETWEEN startDate AND endDate;
Where ? is a parameter for the date you are passing in.
For 2021-08-15, you can write:
WHERE status = 1 AND
'2021-08-15' BETWEEN startDate AND endDate;
If you want the current date, you can actually get that from the database:
SELECT rate, currencyID
FROM hire_rates
WHERE status = 1 AND
curdate() BETWEEN startDate AND endDate;
Just try this then, `$sql = SELECT hireRate FROM hire_rate WHERE startDate<= '$queryDate' and endDate >= '$queryDate'

MySQL Query to Determine Overlapping Timestamps - Schedule System

I have a table that stores shift records for employees.
Simply, there's the following data:
id = Shift ID
employeenum = Employee Number
start = unix timestamp of shift start time
end = unix timestamp of shift end time
date = YYYY-mm-dd description of date the shift starts on
status = shift status (numeric status identifier)
I am currently determining conflicts through a looping php script but it's far too slow. I've searched other questions and can't quite find the answer I'm looking for.
I am trying to come up with a query that will basically give me a list of employeenums that have conflicting shifts within a given time period.
i.e. for the period 2016-07-03 to 2016-07-10, which employees have overlapping start and end timestamps for shifts with a status value of 1 or 7.
Any help would be appreciated.
Thank you!
EDIT
This is essentially the table structure.
id is a primary auto increment key. The table is full of numeric data.
ID is an autoincremented number, employeenum is a 6 digit number, start and end are unix timetamps, date is YYYY-mm-dd date format, overridden is 1 or 0, status is 1,2,3,4,5,6, or 7.
Current loop works by querying:
SELECT * FROM schedule WHERE overridden =0 AND date >=$startdate AND date <= $enddate AND (status = 1 OR status = 7) AND employeenum != 0 ORDER BY date ASC
It then loops through all of those returned shifts to test whether or not another one conflicts with them by executing this query over and over (using the returned start and end values from the results of the above query):
SELECT `employeenum` FROM `schedule` WHERE `overridden` =0 AND `date` >= '$startdate' AND `date` <= '$enddate' AND (`status` = '1' OR `status` = '7') AND ((('$start' > `start`) AND ('$start' < `end`)) OR ((`end` > '$start') AND (`end` < '$end'))) AND `employeenum` = '$employee';"
If there is a result, it pushes the employee number to an array of employees with conflicts. This then prevents the loop from checking for that employee again.
At any given time there could be 10,000 records, so it's executing 10,000+ queries. These records represent only 100-200 employees, so I am looking for a way to query one time to see if there are any overlapping (start and end overlap with another start or end) records between two date values for one employeenum without having to query the database 10,000 times.
This Query will give you the shift id, the date, the employee number, the conflicting employee numbers and a count of conflicting shifts. You have a ton of shifts that conflict in your dataset!!!
SELECT `schedule_test`.`id`, `schedule_test`.`date`, `schedule_test`.`employeenum`, GROUP_CONCAT(DISTINCT`join_tbl`.`employeenum`), COUNT(`join_tbl`.`employeenum`)
FROM `schedule_test`
INNER JOIN `schedule_test` AS `join_tbl` ON
`schedule_test`.`date` = `join_tbl`.`date`
AND (`join_tbl`.`status` = 1 OR `join_tbl`.`status` = 7)
AND (`join_tbl`.`start` BETWEEN `schedule_test`.`start` AND `schedule_test`.`end`
OR `join_tbl`.`end` BETWEEN `schedule_test`.`start` AND `schedule_test`.`end`)
AND `schedule_test`.`id` != `join_tbl`.`id`
WHERE (`schedule_test`.`status` = 1 OR `schedule_test`.`status` = 7)
GROUP BY `schedule_test`.`id`
ORDER BY `schedule_test`.`date`
Adapted from #cmorrissey 's answer. THANK YOU!!
SELECT `schedule_test`.`id`, `schedule_test`.`date`,
`schedule_test`.`employeenum`,
GROUP_CONCAT(DISTINCT`join_tbl`.`employeenum`),
COUNT(`join_tbl`.`employeenum`)
FROM `schedule_test`
INNER JOIN `schedule_test` AS `join_tbl` ON
`schedule_test`.`date` = `join_tbl`.`date`
AND (`join_tbl`.`status` = 1 OR `join_tbl`.`status` = 7)
AND (`join_tbl`.`employeenum` = `schedule_test`.`employeenum`)
AND (`join_tbl`.`start` BETWEEN `schedule_test`.`start` AND `schedule_test`.`end`
OR `join_tbl`.`end` BETWEEN `schedule_test`.`start` AND `schedule_test`.`end`)
AND `schedule_test`.`id` != `join_tbl`.`id`
WHERE (`schedule_test`.`status` = 1 OR `schedule_test`.`status` = 7)
GROUP BY `schedule_test`.`id`
ORDER BY `schedule_test`.`date`

Combining two MYSQL Queries into a single one

I am trying to combine two MYSQL Queries into one. What I want to do is select the first and last row added for each day and subtract the last column for that day from the first column of that day and output that. What this would do is give me a net gain of XP in this game for that day.
Below are my two queries, their only difference is ordering the date by DESC vs ASC. the column in the database that i want to subtract from each other is "xp"
$query = mysql_query("
SELECT * FROM (SELECT * FROM skills WHERE
userID='$checkID' AND
skill = '$skill' AND
date >= ".$date."
ORDER BY date DESC) as temp
GROUP BY from_unixtime(date, '%Y%m%d')
");
$query2 = mysql_query("
SELECT * FROM (SELECT * FROM skills WHERE
userID='$checkID' AND
skill = '$skill' AND
date >= ".$date."
ORDER BY date DESC) as temp
GROUP BY from_unixtime(date, '%Y%m%d')
");
SELECT FROM_UNIXTIME(date, '%Y%m%d') AS YYYYMMDD, MAX(xp)-MIN(xp) AS xp_gain
FROM skills
WHERE userID = '$checkID'
AND skill = '$skill'
AND date >= $date
GROUP BY YYYYMMDD
This assumes that XP always increases, so it doesn't need to use the times to find the beginning and ending values.
If that's not a correct assumption, what you want is something like this:
SELECT first.YYYYMMDD, last.xp - first.xp
FROM (subquery1) AS first
JOIN (subquery2) AS last
ON first.YYYYMMDD = last.YYYYMMDD
Replace subquery1 with a query that returns the first row of each day, and subquery2 with a query that returns the last row of each day. The queries you posted in your question don't do this, but there are many SO questions you can find that explain how to get the highest or lowest row per group.

MySQL: Calculate sum total of all the figures in a column where has specific date

How can I get the sum of the column price for a specific month.
The date column is a varchar(10) and the date format is European ( dd-mm-yy ).
Here is a sample of my table:
Currently to select all sum of price I use:
case 'get':
$q=mysql_real_escape_string($_GET['q']);
$query="SELECT sum(price) FROM Fuel";
$result = mysql_query($query);
$json = array();
while($row = mysql_fetch_array($result))
{
$json['price']=$row['price'];
}
print json_encode($json);
mysql_close();
break;
So how can I get the sum of column price for month 09-2012.
First change the data type of your date column (remember to update your application code appropriately):
ALTER TABLE Fuel ADD newdate DATE;
UPDATE Fuel SET newdate = STR_TO_DATE(date, '%d-%m-%Y');
ALTER TABLE Fuel DROP date, CHANGE newdate date DATE FIRST;
Then you can:
SELECT SUM(price) FROM Fuel WHERE date BETWEEN '2012-09-01' AND '2012-09-30'
This will work for you:
SELECT
sum(price)
FROM Fuel
WHERE datefield = 'somedate';
But you have to watch out the format entered in the date parameter, because it will be compared as a string literal not as a date object. However, you should store these dates in a column of data type DATE instead.
Update:
How can I select sum for all months with 09?
To select only records for a specific month, you can use the MySQL function MONTH like so:
SELECT
SUM(price)
FROM Fuel
WHERE MONTH(`date`) = 9;
SQL Fiddle Demo

MySQL - Select the least day of the current week, not necessarily the first day of the week

Using PHP/MySQL
I'm trying to create a select statement that gets the data from the least day of the current week (I'm using it to show data on a certain player 'this week'). The week starts on Sunday. Sundays's data may not always exist therefore if the Sunday data isn't found then it would use the next earliest day found, Monday, Tuesday, etc.
My date column is named 'theDate' and the datatype is 'DATE'
The query would need to be something like:
SELECT *
FROM table_name
WHERE name = '$username'
AND [...theDate = earliest day of data found for the current week week]
LIMIT 1
It would return a single row of data.
This is a query I tried for getting the 'this week' data, It doesn't seem to work correctly on Sunday's it shows nothing:
SELECT *
FROM table_name
WHERE playerName = '$username'
AND YEARWEEK(theDate) = YEARWEEK(CURRENT_DATE)
ORDER BY theDate;
This is the query that I'm using to get 'this months' data and it works even if the first day of the months data is not found, it will use the earliest date of data found in the current month/year (this query works perfect for me):
SELECT *
FROM table_name
WHERE playerName = '$username'
AND theDate >= CAST( DATE_FORMAT( NOW(),'%Y-%m-01') AS DATE)
ORDER BY theDate
LIMIT 1
Without trying this, you probably need an inner query:
select *
from table_name tn
where tn.the_date =
(select min(the_date)
from table_name
where WEEKOFYEAR(the_date) = WEEKOFYEAR(CURDATE())
and YEAR(the_date) = YEAR(CURDATE()))
viz, give me the row(s) in the table with a date equal to the earliest date in the table in the current week and year.
Try this
SELECT * FROM table_name WHERE name = '$username'
AND your_data IS NOT NULL
AND WEEK(the_date,0 = WEEK(NOW(),0))
ORDER BY DATE_FORMAT(the_date,'%w') ASC
Try the following, replace YOUR_DATE with the date from the column you want (theDate):
SELECT ADDDATE(YOUR_DATE, INTERVAL 1-DAYOFWEEK(YOUR_DATE) DAY)
FirstDay from dual
Did you try:
SELECT ADDDATE(theDate , INTERVAL 1-DAYOFWEEK(theDate ) DAY) FirstDay
FROM table_name
WHERE playerName = '$username'
ORDER BY theDate DESC
LIMIT 1

Categories