CakePHP 3.6: fetchAll()with conditions - php

I would like to add search functionality in my view. The problem is that I get data from raw sql like this so I dont know how to filter the results:
$conn = ConnectionManager::get('default');
$stmt = $conn->execute('SELECT c.id as customerid, CONCAT(c.name, " ", c.surname) as customer, s.title as title, s.length, cs.created , DATE_ADD(cs.created, INTERVAL s.length DAY) as expiring_date, DATEDIFF(DATE_ADD(cs.created, INTERVAL s.length DAY), NOW()) as days_left
FROM customers c
JOIN customer_service_types cs on c.id = cs.customer_id
JOIN service_types s on cs.service_type_id = s.id
WHERE s.is_subscription = 1 and DATE_ADD(cs.created, INTERVAL s.length DAY) > DATE_ADD(NOW(), INTERVAL -30 DAY)
ORDER BY expiring_date');
$expiringServices = $stmt->fetchAll('assoc');
//debug($expiringServices,true);
$this->set(compact('expiringServices'));
Is it possible to filter the results by a form input? I want the user to filter the results by entering the name in a text field and compare it with customer field which returns from the sql query. One guess is the fetchAll(PDO::FETCH_FUNC, fun_name) but I dont know how to implement it.

Related

How to display data from today's date and month to the next 3 months only in codeigniter?

So, I have employee contract data that will expire, I want to display the employee data for today's month and date for the next 3 months. I've tried using DATEADD or DATE_ADD but it still doesn't work. Please help
This is my query:
SELECT a.fullname, a.employee_id, a.id_number, b.date_contract_from, b.date_contract_to AS expired,
b.is_current, b.is_deleted, b.employment_status
FROM hr_employees a
INNER JOIN hr_employee_jobs b
ON a.id = b.employee
WHERE b.date_contract_to >= NOW()
AND b.employment_status IN ('1', '2')
AND b.is_current = 1
AND b.is_deleted = 0 AND a.is_deleted = 0
GROUP BY b.employee
ORDER BY b.date_contract_to ASC
This is an example of how it looks. So, the expiry date in April should not appear.
this is the query view
You can use date between in your Query and DATE_ADD function like this.
SELECT a.fullname, a.employee_id, a.id_number, b.date_contract_from, b.date_contract_to AS expired,
b.is_current, b.is_deleted, b.employment_status
FROM hr_employees a
INNER JOIN hr_employee_jobs b
ON a.id = b.employee
WHERE b.date_contract_to BETWEEN now() AND DATE_ADD(now(), INTERVAL 3 MONTH)
AND b.employment_status IN ('1', '2')
AND b.is_current = 1
AND b.is_deleted = 0 AND a.is_deleted = 0
GROUP BY b.employee
ORDER BY b.date_contract_to ASC

count occurences in 2 tables

I have a table called tasks (id, date, id_user ).
I have an other table called calendar (id, date ).
to find the number of occurrences of the date field for a user between 2 dates I use the query :
$test1 = date(Y-m-d', strtotime('-7'));
$test2 = date('Y-m-d');
$query= $connect->prepare("SELECT *, COUNT(*) AS counter FROM tasks WHERE matricule ='".$_SESSION['matricule']."' AND date < '".$test2."' AND date >= '".$test1."' GROUP BY date");
This query works.
I also want to display 0 for dates that are not in my table tasks but are in the table calendar
You want to count the daily tasks performed by a given user over a range of days, including the days without tasks.
If you have a calendar table - say calendar(dt), where dt is a date - you can do:
select c.dt, count(t.date) as counter
from calendar c
left join tasks t
on t.matricule = :matricule
and t.date = c.dt
where c.date >= :start_date and c.date < :end_date
group by c.dt
:matricule, :start_date and :end_date are parameters to the query; you should really be using prepared statements instead of concatenating POSTed values in the query string, which opens up your code to SQL injection.
If the time range always is the last week:
where c.date >= current_date - interval 7 day and c.date < current_date
Note how the aggregation differs from your original code: columns in the select clause are repeated in the group by clause (left apart those that are aggregated).

get monthly record of employees in one query using mysql

I am using this query for getting monthly record of employees those are present and absent.
However i am getting the result for one employee by using this query but for all employees it doesn't seems to work.
SELECT
m.emp_id AS `Empid`,
d.dt AS `AbsentDate`,
(CASE
WHEN p.punch_status IS NULL THEN 'A'
ELSE p.punch_status
END) s
FROM
(SELECT
DATE(t.added_date) AS dt
FROM
pmc_attendance t
WHERE
DATE(t.added_date) >= '2018-08-01'
AND DATE(t.added_date) < DATE_ADD('2018-08-31', INTERVAL 1 DAY)
GROUP BY DATE(t.added_date)
ORDER BY DATE(t.added_date)) d
CROSS JOIN
tbl_admin_users m
LEFT JOIN
pmc_attendance p ON DATE(p.added_date) >= d.dt
AND DATE(p.added_date) < d.dt + INTERVAL 1 DAY
AND p.emp_id = m.emp_id
WHERE
p.emp_id IS NULL AND m.emp_id = '000838'
GROUP BY d.dt
ORDER BY m.emp_id , d.dt
I am using two tables 1. tbl_admin_users- employee data stored 2. pmc_attendance- present records of employees.
in query if i have passed the and m.emp_id='000838' it works fines but i want to show all records for all employees. any suggestions how i can optimize this query.
There are a couple of ways to structure this query. I can see what yuo are doing, and I think the only issue is with your group by clauses. You dont need them as everything should be distinct. Your status will always be 'A' as you are only getting rows where there is no punch for the employee for the day, so you can also take out the case statement.
SELECT
m.emp_id AS Empid,
d.dt AS AbsentDate,
'A' s
FROM
(
SELECT distinct DATE(t.added_date) AS dt
FROM pmc_attendance t
WHERE t.added_date >= '2018-08-01' AND DATE(t.added_date) < DATE_ADD('2018-08-31', INTERVAL 1 DAY)
) d
CROSS JOIN tbl_admin_users m
LEFT JOIN pmc_attendance p ON p.emp_id = m.emp_id and DATE(p.added_date) >= d.dt AND DATE(p.added_date) < d.dt + INTERVAL 1 DAY
WHERE p.emp_id IS NULL
ORDER BY m.emp_id , d.dt
If you want to include both present and absent, you would need to put your case statement back in, and remove your check WHERE p.emp_id IS NULL
If you have multiple punchs for the day, then you need to resolve it down to a single entry with a MIN/MAX so you only get one row per person per day, and add back in your group by Emp_ID, d.dt

Query not giving the expected result in mysql

My Model function is as below:
function get_newJoineesList($limit=''){
$SQL ="
SELECT userid as uid, CONCAT( firstname, ' ', lastname ) AS name,profileimage, joining_date, role as designation
FROM pr_users_details
INNER JOIN pr_users ON pr_users.id = pr_users_details.userid
LEFT JOIN pr_userroles ON pr_userroles.id=pr_users.userroleid
WHERE joining_date > DATE_SUB( NOW()-1 , INTERVAL 15 DAY )
ORDER BY pr_users_details.id DESC";
if($limit!=''){
$SQL.=" LIMIT ".$limit;
}
$query = $this->db->query($SQL);
$return = $query->result_array();
return $return;
}
I want to get all the results from 15 days ago to now i.e if today is 15th then retrieve all the joining date that falls between 1-15th. But somehow the above query does not work. I am also restricted to use only varchar(15) type as changing this will affect other modules.
snapshot from db2:
snapshot from db1:
The problem is that the way you store the dates do not correspond to how mysql recognizes date literals, therefore the date calculations will be incorrect. You must use the str_to_date() function to convert the strings to valid dates:
SELECT userid as uid, CONCAT( firstname, ' ', lastname ) AS name,profileimage, joining_date, role as designation
FROM pr_users_details
INNER JOIN pr_users ON pr_users.id = pr_users_details.userid
LEFT JOIN pr_userroles ON pr_userroles.id=pr_users.userroleid
WHERE str_to_date(joining_date,'%d-%c-%Y') > DATE_SUB( NOW()-1 , INTERVAL 15 DAY )
ORDER BY pr_users_details.id DESC
Also, I would consider using curdate() instead of now() because you deal with dates only, not times. Using now() may have interesting side effects of excluding dates that are exactly 15 days ago because of the time component.

Min value from Database in MySQL

Am trying to find the min value from past 30 days, in my table there is one entry for every day, am using this query
SELECT MIN(low), date, low
FROM historical_data
WHERE name = 'bitcoin'
ORDER BY STR_TO_DATE(date,'%d-%m-%Y') DESC
LIMIT 7
But this value not returing the correct value. The structure of my table is
Table structure
And table data which is store is like this
Table data style
Now what i need is to get the minimum low value. But my query not working it give me wrong value which even did not exist in table as well.
Updates:
Here is my updated Table Structure.
enter image description here
And here is my data in this table which look like this
enter image description here
Now if you look at the data, i want to check the name of token omisego and fatch the low value from past 7 days which will be from 2017-12-25 to 2017-12-19
and in this cast the low value is 9.67, but my current query and the query suggested by my some member did not brings the right answer.
Update 2:
http://rextester.com/TDBSV28042
Here it is, basically i have more then 1400 coins and token historical data, which means that there will me more then 1400 entries for same date like 2017-12-25 but having different name, total i have more then 650000 records. so every date have many entries with different names.
To get the lowest row per group you could use following
SELECT a.*
FROM historical_data a
LEFT JOIN historical_data b ON a.name = b.name
AND a.low > b.low
WHERE b.name IS NULL
AND DATE(a.date) >= '2017-12-19' AND DATE(a.date) <= '2017-12-25'
AND a.name = 'omisego'
or
SELECT a.*
FROM historical_data a
JOIN (
SELECT name,MIN(low) low
FROM historical_data
GROUP BY name
) b USING(name,low)
WHERE DATE(a.date) >= '2017-12-19' AND DATE(a.date) <= '2017-12-25'
AND a.name = 'omisego'
DEMO
For last 30 day of 7 days or n days you could write above query as
SELECT a.*, DATE(a.`date`)
FROM historical_data2 a
LEFT JOIN historical_data2 b ON a.name = b.name
AND DATE(b.`date`) >= CURRENT_DATE() - INTERVAL 30 DAY
AND DATE(b.`date`) <= CURRENT_DATE()
AND a.low > b.low
WHERE b.name IS NULL
AND a.name = 'omisego'
AND DATE(a.`date`) >= CURRENT_DATE() - INTERVAL 30 DAY
AND DATE(a.`date`) <= CURRENT_DATE()
;
DEMO
But note it may return more than one records where low value is same, to choose 1 row among these you have specify another criteria to on different attribute
Consider grouping the same and running the clauses
SELECT name, date, MIN(low)
FROM historical_data
GROUP BY name
HAVING name = 'bitcoin'
AND STR_TO_DATE(date, '%M %d,%Y') > DATE_SUB(NOW(), INTERVAL 30 DAY);
Given the structure, the above query should get you your results.
// Try this code ..
SELECT MIN(`date`) AS date1,low
FROM historical_data
WHERE `date` BETWEEN now() - interval 1 month
AND now() ORDER by low ASC;

Categories