How do I Compare outer variable from a nested loop in php - php

I'm fetching data from two table Tenders and payments I want to display monthly payments with monthly tenders in on array.
But I need to compare if the month and year from the first loop is the same as the month and year from the nested loop
$first_sql = "SELECT YEAR(toll.transaction_date) 'year', MONTHNAME(toll.transaction_date) 'month', COUNT(toll.toll_id) 'count', SUM(toll.tender) 'tender'
FROM toll WHERE company_id = '$COMPANY_ID'
GROUP BY YEAR(toll.transaction_date), MONTHNAME(toll.transaction_date), MONTH(toll.transaction_date)
ORDER BY YEAR(toll.transaction_date) DESC, MONTH(toll.transaction_date) DESC limit 5;";
$scnd_sql = "SELECT YEAR(company_payment_detail.payment_date) 'year', MONTHNAME(company_payment_detail.payment_date) 'month', SUM(company_payment_detail.payment_amount) 'payment'
FROM company_payment_detail
JOIN company_account ON company_payment_detail.company_account_id = company_account.company_account_id
JOIN company ON company.company_id = company_account.company_id
WHERE company_account.company_id = '$COMPANY_ID'
GROUP BY YEAR(company_payment_detail.payment_date), MONTHNAME(company_payment_detail.payment_date),MONTH(company_payment_detail.payment_date)
ORDER BY YEAR(company_payment_detail.payment_date) DESC, MONTH(company_payment_detail.payment_date) DESC limit 5";
The Results
The Loops
$run_first_sql= $conn->query($first_sql);
$run_scnd_sql = $conn->query($scnd_sql);
$chart_data = [];
//first loop
while($row= $run_first_sql->fetch_assoc()){
$arr1 = array(
'y' => $row['year'],
'm' => $row['month'],
'c' => (int)$row['count'],
't' => (float)$row['tender']
);
while($row2= $run_scnd_sql->fetch_assoc()){
if($row['year'] == $row2['year'] && $row['month'] == $row2['month']){
$arr2 = array(
'p' =>(float)$row2['payment'],
);
}else{
$arr2 = array(
'p' =>(float)0,
);
}
}
$arr1 = array_merge($arr1, $arr2);
array_push($chart_data1, $arr1);
}
print_r($chart_data1);

Do a LEFT JOIN of the two queries. If there's no row in the second query for the same month, you'll get NULL in those columns.
SELECT t1.year, t1.month, t1.count, t1.tender, IFNULL(t2.payment, 0) AS payment
FROM (
SELECT YEAR(toll.transaction_date) 'year', MONTHNAME(toll.transaction_date) 'month', COUNT(toll.toll_id) 'count', SUM(toll.tender) 'tender'
FROM toll WHERE company_id = '$COMPANY_ID'
GROUP BY year, month
ORDER BY year DESC, month DESC
limit 5) AS t1
LEFT JOIN (
SELECT YEAR(company_payment_detail.payment_date) 'year', MONTHNAME(company_payment_detail.payment_date) 'month', SUM(company_payment_detail.payment_amount) 'payment'
FROM company_payment_detail
JOIN company_account ON company_payment_detail.company_account_id = company_account.company_account_id
JOIN company ON company.company_id = company_account.company_id
WHERE company_account.company_id = '$COMPANY_ID'
GROUP BY year, month
ORDER BY year DESC, month DESC
limit 5) AS t2
ON t1.year = t2.year AND t1.month = t2.month

You can perform that in a single query, the year and month of both table can be used as their relationship. The query will be looked like this:
$sql = 'SELECT * FROM tenders, payments WHERE tenders.year=payments.year AND tenders.month=payments.month';
while($row = $sql ->fetch_assoc()){
$data = array(
'month' => $row2['month'],
'year' => $row2['year'],
'count' => $row2['count'],
'tender' => $row2['tender'],
);
}
All the tenders year that is equal to payments year AND tenders month that is equal payments month will be fetched.
So if you are going to stick with your way of fetching data, your if condtion code will look like this:
while($row = $run_first_sql->fetch_assoc()){
while($row2 = $scnd_sql ->fetch_assoc()){
if($row['month'] == $row2['month'] && $row['year'] == $row2['year']){
$data = array(
'month' => $row['month'],
'year' => $row['year'],
'count' => $row['count'],
'tender' => $row['tender'],
);
}
}
}
The data of the first query as it iterate will be checked in your second query which takes time.

Related

Include all column from select to groupBy mysql

I have a query into which I need to add all columns from select to groupBy clause. This is just an example, I've around 20-25 columns to be selected and a long query to deal with.
Eg = SELECT contact.id as id, contact.name as name,
IF ( contact.type = 'type1', NULL, contact.organization_name),
contact.occupation as occupation, contact.gender as gender
FROM table_name
WHERE <condition>
GROUP BY contact.id.
What I have in an array is this :
$select = array(
'id' => 'contact.id as id',
'name' => 'contact.name as name',
'type' => IF ( contact.type = 'type1', NULL, contact.organization_name),
'occupation' => 'contact.occupation as occupation',
'gender' => 'contact.gender as gender',
);
$groupBy = 'GROUP BY contact.id';
Now I have to dynamically update groupBy clause to include all the columns from the $select array from php code.
I've done this :
foreach ($select as $key => $val) {
$alias = explode(' as ', $val);
if ($alias[0] != 'contact_a.id') {
$selectColAlias[] = $alias[0];
}
}
$groupBy .= ', ' . implode(', ', $selectColAlias);
This is happening correctly if type is not included in the $select array.
Is there anything which would populate my groupBy clause to include all the columns from the select clause ?
As I have ONLY_FULL_GROUP_BY mode enabled. This gives an error if the above thing is not done.

How to access a particular value from mysql database using php?

This is my php script that selects everything from invoiceNo where invoiceNo is distinct.
<?php
require 'init.php';
$query = 'SELECT * FROM `selected_items` WHERE invoiceNo IN ( SELECT DISTINCT ( invoiceNo) AS invoiceNo FROM selected_items ) GROUP BY invoiceNo;';
$res = mysqli_query($con, $query);
$result = [];
while ($row = mysqli_fetch_array($res)) {
array_push($result, [
'custInfo' => $row[0],
'invoiceNo' => $row[1],
'barcode' => $row[2],
'description' => $row[3],
'weight' => $row[4],
'rate' => $row[5],
'makingAmt' => $row[6],
'net_rate' => $row[7],
'itemTotal' => $row[8],
'vat' => $row[9],
'sum_total' => $row[10],
'bill_type' => $row[11],
'date' => $row[12],
'advance' => $row[13],
'balance' => $row[14],
]);
}
echo json_encode(['result' => $result]);
mysqli_close($con);
Right now this script gives me the first value from sum_total i.e it gives me the first row from my database how can I get the last row.I am new to programming any suggestions or help is appreciated.Thanks :)
Select * From (
SELECT t.*,
#rownum := #rownum + 1 AS rank
FROM selected_items t,
(SELECT #rownum := 0) r order by rank DESC
) si GROUP BY si.invoiceNo;
This query solved my problem
Try this, i think this is you want, may it help
$query ="SELECT max( `sum_total` ) FROM `selected_items` GROUP BY invoiceNo;";
try like this :
$query ="SELECT * FROM `selected_items` WHERE invoiceNo IN ( SELECT DISTINCT ( invoiceNo) AS invoiceNo FROM selected_items ) ORDER BY `sum_total` DESC";
$query ="SELECT max( `sum_total` ) FROM selected_items";
Where column_name can be vary.
If you need to get only last record use limit.
$query ="SELECT * FROM `selected_items` GROUP BY invoiceNo ORDER BY `sum_total` DESC limit 1;
If you need to get highest to lowest sum_total record try the below code,
$query ="SELECT * FROM `selected_items` where `sum_total` = (SELECT max( `sum_total` ) FROM `selected_items` GROUP BY invoiceNo) GROUP BY invoiceNo ORDER BY `sum_total` DESC;

How to Implement this Mysql query into Zend framework 1 using dbSelect

SELECT
CONCAT(us.user_id,' ', us.name),
UPPER(sc.so_number) Order_no ,
sh.upc UPC,re.label Error,
(SELECT count(*) FROM order_checker_scan scan WHERE scan.so_number =sh.so_number and scan.upc=sh.upc and scan.user_id!=0
and DATE_FORMAT(scan_time,'%Y-%m-%d') >= '2015-11-01' ) AS
prev_data,
(select CONCAT(u.user_id,' ', u.name) from users u,picklist_history p where u.user_id=p.user_id and
p.so_number=sh.so_number limit 1) as picker,
sh.item_key Times,
DATE_FORMAT(sc.date_started,'%b%d %Y %h:%i%p') datetime,sh.qty_required QTY
FROM
order_checker_short sh,
order_checker_header
sc,order_checker_short_reason re,
users us
WHERE sh.so_number=sc.so_number AND
sh.reason_id=re.reason_id AND
sc.created_by=us.user_id And
sc.created_by!=0 AND
DATE_FORMAT(date_started,'%Y-%m-%d') between '2015-11-16' and '2015-11-17' AND
sh.reason_id !=0 AND
sh.upc !=1
GROUP BY sc.so_number,sh.upc
ORDER BY sc.date_started DESC, sc.so_number DESC , sh.upc ASC
Please test the following:
// 1st subselect
$prevDataSelect = $db->select()
->from(array('scan' => 'order_checker_scan'), array('count(*)'))
->where('scan.so_number = sh.so_number')
->where('scan.upc = sh.upc')
->where('scan.user_id != 0')
->where("DATE_FORMAT(scan_time,'%Y-%m-%d') >= '2015-11-01'");
// 2nd subselect
$pickerSelect = $db->select()
->from(array('u' => 'users', 'p' => 'picklist_history'), array("CONCAT(u.user_id,' ', u.name)"))
->where('u.user_id = p.user_id')
->where('p.so_number = sh.so_number')
->limit(1);
// Main selection
$mainSelect = $db->select()
->from(
// tables
array(
'sh' => 'order_checker_short',
'sc' => 'order_checker_header',
're' => 'order_checker_short_reason',
'us' => 'users',
),
// columns
array(
'SomeName' => "CONCAT(us.user_id, ' ', us.name)",
'Order_no' => 'UPPER(sc.so_number)',
'UPC' => 'sh.upc',
'Error' => 're.label',
'prev_data' => new Zend_Db_Expr('(' . $prevDataSelect . ')'),
'picker' => new Zend_Db_Expr('(' . $pickerSelect . ')'),
'Times' => 'sh.item_key',
'datetime' => "DATE_FORMAT(sc.date_started,'%b%d %Y %h:%i%p')",
'QTY' => 'sh.qty_required',
)
)
// AND WHERE clauses
->where('sh.so_number = sc.so_number')
->where('sh.reason_id = re.reason_id')
->where('sc.created_by = us.user_id')
->where('sc.created_by != 0')
->where("DATE_FORMAT(date_started, '%Y-%m-%d') between '2015-11-16' and '2015-11-17'")
->where('sh.reason_id != 0')
->where('sh.upc != 1')
// GROUP BY clause
->group(array('sc.so_number', 'sh.upc'))
->order(array('sc.date_started DESC', 'sc.so_number DESC', 'sh.upc ASC'));
If doesn't work please tell me what's the output of $mainSelect->assemble()

How to run subqueries in cakephp

Cakephp 2.6
I have a Model, Temps, which has many tickets. In the index view of Temps I want to return for each record, the ticket with the date closest to the current date.
In mySQL it can be done as
'SELECT expiry_date FROM uploads WHERE expiry_date > CURDATE() ORDER BY expiry_date ASC LIMIT 1'
But I don't know how to run this as a sub query. My Current query to generate my results is as follows: (bearing in mind this has been configured for datatables) Tickets is an alias for the Upload Model
public function getAjaxIndexData($data) {
$tokens = explode(" ", $data['searchString']);
$conditions = array(
$this->alias . '.deleted' => false,
'OR' => array(
'CONCAT(' . $this->alias . '.first_name," ",' . $this->alias . '.last_name) LIKE' => '%' . implode(' ', $tokens) . '%',
),
$data['columnsFilter']
);
$fields = array(
'id',
'full_name',
'pps_number',
'mobile',
'email',
'start_date',
'time_served'
);
$order = array(
$data['orderField'] => $data['order']
);
$contain = array(
'LocalOffice.name',
);
$options = array(
'conditions' => $conditions,
'fields' => $fields,
'order' => $order,
'contain' => $contain,
'limit' => $data['limit'],
'offset' => $data['start']
);
$optionsNoFields = array(
'conditions' => $conditions,
'contain' => $contain,
);
$result['draw'] = $data['draw'];
$result['recordsTotal'] = $recordTotal = $this->find('count');
$result['recordsFiltered'] = $this->find('count', $optionsNoFields);
$result['data'] = $this->find('all', $options); //standard search
$result['data'] = $this->formatTable($result['data']);
return json_encode($result);
}
Within this query I would like to add a field that shows the nearest expiry date for each Temp.
How would I construct this?
Dynamically create a virtual field:
$this->virtualFields['nearest'] = '(SELECT expiry_date FROM uploads WHERE expiry_date > CURDATE() AND uploads.owner_id = '.$this->alias.'.ticket_id ORDER BY expiry_date ASC LIMIT 1')';
Then adjust your fields array
$fields = array(
'id',
'full_name',
'pps_number',
'mobile',
'email',
'start_date',
'time_served',
'nearest'
);
Also, the query could be rewritten as ("temp" needs to be replaced with the model alias)
SELECT MIN(expiry_date)
FROM uploads
WHERE expiry_date > CURDATE()
AND uploads.owner_id = temp.ticket_id;
Which means that a potentially better performing query would be to move that subquery out of the columns of the SELECT statement to a JOIN. For example:
SELECT *
FROM temp
LEFT JOIN (SELECT MIN(expiry_date) AS expiry,owner_id
FROM uploads
WHERE expiry_date > CURDATE())
GROUP BY owner_id) AS next_dates
ON next_dates.owner_id = temp.ticket_id;

Getting column value when SQL query has aliases

I have a SQL query that has alias in it. The problem is, when I try to get the values of columns it doesn't show the correct values:
$sql = "SELECT p.ID, p.ProfileID, p.ModuleID, p.View, p.Add, p.Edit, p.Delete, m.Name, m.ID FROM permission AS p, module AS m WHERE p.ModuleID = m.ID ORDER BY p.ProfileID ASC, m.Name ASC";
$result = array();
$i = 0;
foreach ($this->dbconnect->query($sql) as $row)
{
$result[$i] = array(
'ID' => $row['p.ID'],
'ProfileID' => $row['p.ProfileID'],
'ModuleID' => $row['p.ModuleID'],
'View' => $row['p.View'],
'Add' => $row['p.Add'],
'Edit' => $row['p.Edit'],
'Delete' => $row['p.Delete']);
$i += 1;
}
Running shows no value when in the database it's actually 10.
If I change the above code to the following:
$sql = "SELECT p.ID, p.ProfileID, p.ModuleID, p.View, p.Add, p.Edit, p.Delete, m.Name, m.ID FROM permission AS p, module AS m WHERE p.ModuleID = m.ID ORDER BY p.ProfileID ASC, m.Name ASC";
$result = array();
$i = 0;
foreach ($this->dbconnect->query($sql) as $row)
{
$result[$i] = array(
'ID' => $row['ID'],
'ProfileID' => $row['ProfileID'],
'ModuleID' => $row['ModuleID'],
'View' => $row['View'],
'Add' => $row['Add'],
'Edit' => $row['Edit'],
'Delete' => $row['Delete']);
$i += 1;
}
Miraculously, running shows the value of m.ID instead of p.ID. It is strange why the first example is incorrect. Am I missing something here?
You should something like this...
SELECT p.ID as p_ID, ...
And
'ID' => $row['p_ID'],
Use aliases in SELECT to each column, which are same:
$sql = "SELECT p.ID AS permission_id, p.ProfileID, p.ModuleID, p.View, p.Add, p.Edit, p.Delete, m.Name, m.ID AS module_id FROM permission AS p, module AS m WHERE p.ModuleID = m.ID ORDER BY p.ProfileID ASC, m.Name ASC";
then:
foreach(...)
{
$result[$i] = array(
'Perm_ID' => $row['permission_id'],
'Module_ID' => $row['module_id'],
...
}

Categories