Having trouble inserting dates into MySQL - php

I'm trying to insert some dates (a given date, +1 day and +1 month) into MySQL with PHP (CI).
Here is my CI active record code:
the variable $last_period_end returns 2012-02-20, the field it is trying to insert it into is MySQL DATE format.
$data = array(
'user_id' => $user_id,
'period_start' => "DATE_ADD($last_period_end, INTERVAL 1 DAY)",
'period_end' => "DATE_ADD($last_period_end, INTERVAL 1 MONTH)",
'cost' => $cost
);
$result = $this->db->insert('invoices', $data);
if ( $result )
return true;
else
return false;
This inserts 0000-00-00 rather than what I would like it to.
I have also tried pure SQL:
INSERT INTO betterbill.invoices (user_id, period_start, period_end, cost)
VALUES(18, DATE_ADD(2012-02-20, INTERVAL 1 DAY), DATE_ADD(2012-02-20, INTERVAL 1 MONTH), 100.05);
Interestingly this inserts nothing, rather than 0000-00-00
Any input is appreciated!

You miss the quote ' for the date string.
$data = array(
'user_id' => $user_id,
'period_start' => "DATE_ADD('$last_period_end', INTERVAL 1 DAY)",
'period_end' => "DATE_ADD('$last_period_end', INTERVAL 1 MONTH)",
'cost' => $cost
);

Related

cakephp 3.x datetime field comparison in query not returning correct result

Trying to get all the records with which has been created 24 hr or prior. Here 'created' is a datatime field. I've three records in DB which must satisfy this condition, but returning 0 records.
$my_table_tbl = TableRegistry::get('my_table');
$records = $my_table_tbl
->find()
->where([
'created <' => '(NOW() - INTERVAL 1 DAY)',
'status' => 'pending'
])
->toArray();
CakePHP will always treat the right side of a clause as a variable binding. That means (NOW() - INTERVAL 1 DAY) is interpreted as a string value.
You can check what SQL is generated by converting the query to a string.
$query = $my_table_tbl->find()
->where([
'created <' => '(NOW() - INTERVAL 1 DAY)',
'status' => 'pending'
]);
dd((string)$query);
When you output the SQL above it will show created < :c0 instead of your expression.
Use a query object to create a custom expressions.
$q = $my_table_tbl->query();
$query = $my_table_tbl
->find()
->where([
'created <' => $q->newExp('(NOW() - INTERVAL 1 DAY)'),
'status' => 'pending'
]);
dd((string)$query);
When you output the SQL above it will show created < (NOW() - INTERVAL 1 DAY) as expected. This is because CakePHP checks if the values on the right hand are an expression object.

Grouping data to get reports by intervals

I posted a question some time ago on representing data per date horizontally on a datatable.
See here: datatables dates at the top and data cells going from left to right
With the help of that thread I was able to get the data to display how I wanted it. With the dates showing at the top, the service provided on the left and all data associated with any date between the 2 date paramters inside the main body. (If there is no data in a particular date then the < td > will display 0. See here:
http://www.phpwin.org/s/ewbAS6
After manipulating this code further I made the dates of the search dynamic by proving a form with a start date and an end date, and a dropdown with the options of:
Daily
Weekly
Monthly
Quaterly
Yearly
this allows the interval of dates at the top to become dynamic. Of course all this is doing is changing the value of the 2nd parameter inside the date while loop.
WHILE (strtotime($date) <= strtotime($end_date)) {
echo '<th>' . $date . '</th>';
$date = date('Y-m-d', strtotime($date . ' +1day'));
}
with the parameter set at Weekly, the value of +1day becomes +1week, at Monthly; the value becomes +1month and so on.
MY ISSUE:
When the interval is set to daily, the dates with their corresponding attendance counts are displayed correctly but once you try to increase the interval to +1week and above the data does not round up to the week shown. Check this:
[LINK1]Per day: http://www.phpwin.org/s/ewbAS6
[LINK2]Per month: http://www.phpwin.org/s/xRo3I6
Looking at the array (modified on the LINK2)
$result[] = array('Service Name' => 'Health', 'date' => '2017-04-04', 'Attendance' => 5);
$result[] = array('Service Name' => 'Payroll', 'date' => '2017-04-16', 'Attendance' => 5);
$result[] = array('Service Name' => 'Saturday Youth Meeting', 'date' => '2017-04-03', 'Attendance' => 1);
$result[] = array('Service Name' => 'Saturday Youth Meeting', 'date' => '2017-05-03', 'Attendance' => 3);
$result[] = array('Service Name' => 'Payroll', 'date' => '2017-05-03', 'Attendance' => 2);
$result[] = array('Service Name' => 'Payroll', 'date' => '2017-04-11', 'Attendance' => 3);
$result[] = array('Service Name' => 'Payroll', 'date' => '2018-04-03', 'Attendance' => 10);
You can see in the array that there are multiple attendance entries in April, totaling 14 Attendances in that month however during LINK2 where the interval is increased to a month instead of showing 14 for April (which would be the sum of all the dates in that particular month) it shows the value 1.
My live version takes the array from a database so I used the YEAR(), MONTH(), WEEK() and DAY() function on the date and used group by. The query executes how I want it but having issues working on the PHP end.

insert age of account MYSQL query

What would be the best way to find the difference in the two dates start_date and account_add_date then insert into a column called account_age?
What I need is for a user to select a start_date say its January.
Then the date when they added account_add_date say March.
The difference is 2 months so in account_age would be 2,
then in April that 2 would be a 3. May 4, June 5 and so on
Dose anyone know how to do this ?
My current insert query MODEL
function create_bank()
{
$this->load->helper('date');
$new_bank_acc_insert_data = array(
'bank_name' => $this->input->post('bank_name'),
'interest' => ($this->input->post('interest') / 100),
'start_amount' => $this->input->post('start_amount'),
'length' => $this->input->post('length'),
'start_date' => date('Y-m-d',strtotime($this->input->post('start_date'))),
'mem_id' => $this->session->userdata('id'),
'account_add_date' => $this->current_date()
);
$insert = $this->db->insert('bank', $new_bank_acc_insert_data);
return $insert;
}
Idea on finding account age
SELECT DATEDIFF('start_date','account_add_date')
SELECT
(
12* (YEAR(account_add_date) - YEAR(start_date)) +
(MONTH(account_add_date) - MONTH(start_date))
) AS differenceInMonth
FROM
YOUR_TABLE
Although DATEDIFF function returns the difference in two dates in days which is more accurate comparing to the difference in month
Explanation:
Example:
start_date = 2014 March
account_add_date = 2015 January
YEAR(account_add_date) = 2015
YEAR(start_date) = 2014
MONTH(account_add_date) = 1
MONTH(start_date) = 3
So according to the query:
12 * (2015-2014) + (1-3) = 12 * 1 - 2 = 10 (Months)

CakePHP SQL Operation using 'OR'

I am using CakePHP find to retrieve the data. I need to use OR between conditions so i used following query as stated in CakePHP documentation. This works perfectly other times but the problem arises when the field name is same in OR array, Group.arrival_date in this case.
$this->Group->find('all',
array('conditions' => array(
'OR' => array(
'Group.arrival_date' => 'DATE_ADD(CURDATE(), INTERVAL 30 DAY)',
'Group.arrival_date' => 'DATE_ADD(CURDATE(), INTERVAL 7 DAY)'
)
)
));
The SQL it generate is
SELECT `Group`.`id`, `Group`.`rr_no`, `Group`.`package_id`, `Group`.`user_id`,
`Group`.`group_name`, `Group`.`pax`, `Group`.`agent_id`, `Group`.`staff_id`,
`Group`.`arrival_date`, `Group`.`departure_date`, `Group`.`status`, `Group`.`slug`,
`Group`.`book_flight`, `Group`.`allocated_tents`, `Group`.`alert`, `Group`.`alert_seen`
FROM `groups` AS `Group` WHERE `Group`.`arrival_date` = 'DATE_ADD(CURDATE(), INTERVAL 7 DAY)'
It takes the second condition only. For different field name like:
$this->Group->find('all',
array('conditions' => array(
'OR' => array(
'Group.slug' => 'slug1',
'Group.group_name' => 'group1'
)
)
));
The generated SQL is
SELECT `Group`.`id`, `Group`.`rr_no`, `Group`.`package_id`, `Group`.`user_id`,
`Group`.`group_name`, `Group`.`pax`, `Group`.`agent_id`, `Group`.`staff_id`,
`Group`.`arrival_date`, `Group`.`departure_date`, `Group`.`status`, `Group`.`slug`,
`Group`.`book_flight`, `Group`.`allocated_tents`, `Group`.`alert`, `Group`.`alert_seen`
FROM `groups` AS `Group` WHERE ((`Group`.`slug` = 'slug1') OR (`Group`.`group_name` = 'group1'))
Which is as expected. What am i missing in the first find i used? How can i get the above query work? Any help would be greatly appreciated. I am using CakePHP 2.0.
Try:
$this->Group->find('all',
array('conditions' => array(
'OR' => array(
array('Group.arrival_date' => 'DATE_ADD(CURDATE(), INTERVAL 30 DAY)'),
array('Group.arrival_date' => 'DATE_ADD(CURDATE(), INTERVAL 7 DAY)')
)
)
));
Or you could use IN:
$this->Group->find('all',
array('conditions' => array(
'Group.arrival_date' => array('DATE_ADD(CURDATE(), INTERVAL 30 DAY)', 'DATE_ADD(CURDATE(), INTERVAL 7 DAY)')
)
);
For same field, simply put all values you need for OR in an array.
$this->Group->find('all',
array('conditions' => array(
'Group.arrival_date' =>
array('DATE_ADD(CURDATE(), INTERVAL 30 DAY)', 'DATE_ADD(CURDATE(), INTERVAL 7 DAY)' )
)
));

Retrieving mysql statistical data using PHP regular intervals and including null data

So I am trying to build out some nice stats displays for my app. I can do this because I keep hit stats in a table. It simply tracks the hits plus some other nice data and the time it occurs. I can query the db to show me how many hits occurred on a particular day or on each day for the past x days as in the code below. However the code below only returns dates for which there is data. I would like to show the last 30 days of hits regardless of whether a day has a hit or not. Thoughts?
SELECT DATE(time) AS theday, COUNT( * ) AS thecount
FROM stats
WHERE time <= curdate( )
AND time >= DATE_SUB( curdate(), INTERVAL 30 DAY )
GROUP BY theday ORDER BY time DESC
Produces
theday thecount
2011-11-22 5
2011-11-21 9
2011-11-18 10
2011-11-16 1
2011-11-11 2
2011-11-10 15
2011-11-09 2
2011-10-26 1
2011-10-24 6
As you can see it skips dates with no results. I understand why this is, as there are no rows with those dates in the db. I am wondering how I would produce a query that works almost like the above but has all the dates for said interval. IE: the last 30 days.
You have 3 options:
try to iterate the dates in the application logic (php)
generate a (temporary) table filled with the dates you need and left join with it
use mysql stored procedure solution like in this answer
Example for app logic implementation:
<?php
date_default_timezone_set('Europe/Paris');
$startdate = strtotime('2011-11-01 00:00:01');
$days = 60;
$found_data = array( // this is generated by 1 mysql query
array('date_field' => '2011-11-02', 'count' => 5),
array('date_field' => '2011-11-03', 'count' => 1),
array('date_field' => '2011-11-04', 'count' => 6),
array('date_field' => '2011-11-08', 'count' => 9),
array('date_field' => '2011-11-09', 'count' => 3),
array('date_field' => '2011-11-10', 'count' => 5),
array('date_field' => '2011-11-12', 'count' => 1),
array('date_field' => '2011-11-15', 'count' => 1),
array('date_field' => '2011-11-18', 'count' => 4),
array('date_field' => '2011-11-21', 'count' => 9),
array('date_field' => '2011-11-23', 'count' => 1),
array('date_field' => '2011-11-28', 'count' => 8),
array('date_field' => '2011-11-30', 'count' => 6),
);
foreach ($found_data as $counts) { // we convert the results to a usable form, you can do this in the query, too
$count_info[$counts['date_field']] = $counts['count'];
}
for ($i = 0; $i <= $days; $i++) {
$date = date('Y-m-d', $startdate+$i*60*60*24);
printf("%s\t%s\n", $date, array_key_exists($date, $count_info) ? $count_info[$date] : 0);
}
?>

Categories