Combine two SQL query in a while loop - php

Basically, I want to display the combined output of the below sql queries in a table using one while loop. I have a table called participating_institutions which holds unique code and names for all institutions. I also have trades table where each of the institutions can either be a buyer, a seller or both (Yes, an institution can do a trade for its two clients). With the help of good guys here, I was able to match each code in trades table with corresponding names in participating institution table using sql JOIN as indicated in the queries. The first query below will sum all the buy values for each firm and the second query will do same for their sales. However, the table I want to display will have the [Sum(buy_value) + Sum(sell_value)] for each firm in the while loop. How do I achieve this using either mysql or php.
Note: The trade table has two column in it for buy_firm_code and sell_firm_code. The records they hold is the same depending on which side of the trade a firm participated.
Below is what I have done so far.
<?php
$con=mysqli_connect("localhost","db_user","password","database");
$total_value = 0;
$buy_value = 0;
$sell_value = 0;
$firm_name = "";
$institution_code = "";
$display = "";
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$buy_sql="SELECT p.institution_code, p.institution, SUM(t.trade_value)
value_bought FROM trades t JOIN participating_institutions p ON p.institution_code = t.buy_firm_code GROUP BY t.buy_firm_code ORDER BY value_bought DESC";
if ($buy_result = mysqli_query($con, $buy_sql))
{
// Fetch one and one row for buy side
while($row=mysqli_fetch_array($buy_result)) {
$buy_value .= $row['value_bought'].'<br>';
$institution_code .= $row['institution_code'].'<br>';
$firm_name .= $row['institution'].'<br>';
}
}
$sell_sql = "SELECT p.institution_code, p.institution, SUM(t.trade_value) value_sold FROM trades t JOIN participating_institutions p ON p.institution_code = t.sell_firm_code GROUP BY t.sell_firm_code ORDER BY value_sold DESC";
if ($sell_result = mysqli_query($con, $sell_sql))
{
// Fetch one and one row for sale side
while($row=mysqli_fetch_array($sell_result)) {
$sell_value.= $row['value_sold'].'<br>';
$institution_code .= $row['institution_code'].'<br>';
$firm_name.= $row['institution'].'<br>';
}
}
$total_value = $buy_value + $sell_value;
$display .= '<table><tr><td>'.$institution_code.'</td><td>'.$firm_name .'</td><td>'.$total_value.'</td></tr></table>';
echo $display;
// Free result set
mysqli_free_result($buy_result);
mysqli_free_result($sell_result);
mysqli_close($con);
?>
When I run this two problems:
The firms repeat, I guess because I am running two queries. What I
want is one output record for each firm.
I don't get the overall total for each firm rather I get the sum of total buy and total sell of the first record
instead of
Firmcode A: FirmName A: 20,000
Firmcode B: FirmName B: 40,000
Firmcode C: FirmName C: 50,000
I get this
Firmcode A: FirmName A:
Firmcode B: FirmName B: 20,000
Firmcode C: FirmName C:

Thanks guys. I have been able to resolve the issue. I created two views in my database using the two queries above. I then used a third query in my code to join the two views using the SUM aggregate function for my total buy and total sell values. It works perfectly now. Thanks for all your contribution.

Related

Sorting PHP Results of a query on two fields

I'm just starting to learn php. Everything I've researched references an array for sorting but I can't figure out how to make that work in this situation since one of my fields is constantly changing so I can't create a fixed array. Remember, I'm a noob so please explain in detail.
I would like to sort based on two fields how the results are displayed.
The first field on which to sort should be based on "SortOrder" as it correlates to the "TaskSubType" field (Displayed as Ticket Type on forms. TaskSubType has the following values assigned and would work in an array:
MSP = 1
DEDICATED = 2
REMOTE SUPPORT = 3
EXPEDITED = 4
EXPEDITED - $25 = 4
STANDARD = 5
STANDARD - $25 = 5
So if the Ticket Type (TaskSubType) was selected as "Dedicated" then it would be sorted as "2" and if "Standard - $25" was selected as the Ticket Type (TaskSubType) then it would be sorted as "5".
The second field on which I want to sort is the Ticket Number (TicketNumber) field. The value in this field is constantly changing since we have new tickets created every day so I don't know how to sort on this field with an array.
Main Goal: I want to sort the results by Ticket Type according to the numeric value we have assigned to each type which is our repair priority and then sort within all the "Dedicated" or "Standard" to work each ticket in that group in the order it was created (each new ticket counts up by one).
The code below is what I have working up to this point and the weblink below shows how my results are currently displaying:
Webpage where results are shown:
https://fireytech.com/FireytechDatabase/hello.php
Code:
<?php
require '../../db_php/dbconnection.php';
$sql = "SELECT * FROM
Tickets
Left JOIN
Clients
ON Tickets.CustomerNumber=Clients.CustomerNumber
JOIN Contacts
ON Contacts.ContactID=Clients.CustomerNumber
JOIN Equipment
ON Equipment.ContactID=Clients.CustomerNumber
WHERE Equipment.PRINT = '-1' AND Contacts.DispatchContact = '-1' AND TicketStatus = 'Active' AND NOT TicketSubStatus = 'CUSTOMER PICKUP' AND NOT TaskSubType = 'ON-SITE'
";
$result = $conn->query($sql);
echo"<table border='1'>";
echo "<tr><td>Ticket Type</td><td>Ticket Number</td><td>Date Received</td><td>Last Edited</td><td>Last Name</td><td>Followup By</td><td>Sub Status</td><td>Repair Type</td><tr>";
if ($result->num_rows > 0){
while($row = $result->fetch_assoc() ){
$dr= date("m/d/Y", strtotime($row['DateReceived']));
$dl= date("m/d/Y", strtotime($row['DateLastEdited']));
echo "<tr><td>{$row['TaskSubType']}</td><td>{$row['TicketNumber']}</td><td>{$dr}</td><td>{$dl}</td><td>{$row['ContactLast']}</td><td>{$row['FollowupBy']}</td><td>{$row['TicketSubStatus']}</td><td>{$row['ItemType']}</td></tr>";
}
} else {
echo "0 records";
}
echo"</table>";
$conn->close();
?>
Murosadatul gave me the clarity I needed. I had tried the ORDER BY command but didn't realize I need to put it at the end of my SQL query. Below in bold is where I placed it in my code so it worked if anyone else runs into the same problem:
$sql = "SELECT * FROM
Tickets
Left JOIN
Clients
ON Tickets.CustomerNumber=Clients.CustomerNumber
JOIN Contacts
ON Contacts.ContactID=Clients.CustomerNumber
JOIN Equipment
ON Equipment.ContactID=Clients.CustomerNumber
WHERE Equipment.PRINT = '-1' AND Contacts.DispatchContact = '-1' AND TicketStatus = 'Active' AND NOT TicketSubStatus = 'CUSTOMER PICKUP' AND NOT TaskSubType = 'ON-SITE'
->->->->->->-> ORDER BY SortOrder, TicketNumber
"
;
$result = $conn->query($sql);

Mysql join returns results in multiple rows instead of one for every instance

I have three tables: tbl_days, tbl_slots and tbl_bookings as follows.
Customers are supposed to book for a slot in a day.
Am using the following query:
$slots = $this->common->slots();
if ($slots != NULL) {
foreach ($slots as $C):
$start = $C->start;
$stop = $C->stop;
$slotspace= $start." to ".$stop;
$available='Available';
$booked ='Booked';
$sum_col[] = " IF(tbl_bookings.slot_id =". $C->id.",'".$booked."','".$available."') AS '" . $slotspace . "'";
endforeach; }
$sqlquery = $this->db->query("SELECT tbl_days.date_day,
" . implode(",", $sum_col) . "
FROM tbl_days
LEFT JOIN tbl_bookings ON tbl_bookings.date = tbl_days.date_day
LEFT JOIN tbl_slots ON tbl_slots.id = tbl_bookings.slot_id
LEFT JOIN tbl_fields ON tbl_fields.id = tbl_bookings.field_id
");
return $sqlquery->result();
However, the results display as:
Intended result should be:
Please note how booking information displays on multiple rows for the same date.
Dates to be from the date today (for the next 7 days from today)
Display slots for the day on one row.
Display the date regardless of if there is a booking or not, like in date 29th.
Kindly help me on how to go about this.
Please note that am using datatables.
So each entry gets displayed in a new row instead of everything that's connected to each other in 1 row, right? I had the same problem in the past and the solution is a second foreach. The second one should look at all the records and see if one is connected to another.
See my question: Each value is displayed in a new row HTML table

Foreach looping too many times

I'm using this to display information from a queried db in Wordpress. It displays the correct information but it loops it too many times. It is set to display from a SELECT query and depending on the last entry to the db seems to be whether or not it prints double or triple each entry.
foreach ($result as $row) {
echo '<h5><i>'.$row->company.'</i> can perform your window installation for <i>$'.$row->cost.'</i><br>';
echo 'This price includes using<i> '.$row->material.'</i> as your material(s)<br>';
echo '<hr></h5>';
}
Does anyone know what could be producing this error?
Thanks
The query powering that script is:
$result = $wpdb->get_results( "SELECT bp.*, b.company
FROM `windows_brands_products` bp
LEFT JOIN `windows_brands` b
ON bp.brand_id = b.id
JOIN Windows_last_submissions ls
JOIN windows_materials wm
JOIN Windows_submissions ws
WHERE ws.username = '$current_user->user_login'
AND bp.width = ROUND(ls.width)
AND bp.height = ROUND(ls.height)
AND bp.material IN (wm.name)
AND bp.type = ls.type
AND IF (ls.minimumbid != '0.00',bp.cost BETWEEN ls.minimumbid AND ls.maximumbid,bp.cost <= ls.maximumbid)
ORDER BY b.company ASC");
I can't seem to see the duplicate but I agree it must be there.
EDIT-- when I replace the WHERE clause to WHERE ws.username = 'password' , it still repeats. It it displaying a result for each time a result has username='password' , and displaying that set twice as well.
I think you want the following, if you're using MySQLi:
while ($row = $result->fetch_object()) {
echo '<h5><i>'.$row->company.'</i> can perform your window installation for <i>$'.$row->cost.'</i><br>';
echo 'This price includes using<i> '.$row->material.'</i> as your material(s)<br>';
echo '<hr></h5>';
}
Redundant JOIN clauses in my query which was pretty much pulling the same results from two tables (one of which was just a VIEW of the other).

Is it possible to create a database call outside of a required loop?

I'm trying to display and sort an array by an average created using data from a database. I'm retrieving three variables from the database and creating an average from these values. This value is then placed inside a new array to be sorted along with the rest of the database data.
Am I right in thinking that having the SQL query inside the loop isn't a great idea? (Performance issue?)
Is there any alternative that's available? I've attached the code below:
^ database connection/query string to retrieve all data...
$result = $stmt_business_list->fetchAll(PDO::FETCH_ASSOC);
$items = array();
foreach($result as $row){
$single_business_id = $row['id'];
$name = $row['name'];
//Query to get ALL the service, value and quality ratings for certain business
$test_query = "SELECT * FROM rating WHERE business_id = $single_business_id";
$test_query_stmt = $dbh->prepare($test_query);
$test_query_stmt->execute();
$test_row = $test_query_stmt->fetchAll(PDO::FETCH_ASSOC);
$total_value = $total_quality = $total_service = 0;
foreach($test_row as $review)
{
$total_value += $review['value'];
$total_quality += $review['quality'];
$total_service += $review['service'];
}
$bayesian_value = (($set_site_average_review_count * $set_site_average_review_score) + $total_value) / ($set_site_average_review_count + $business_review_count);
$bayesian_quality = (($set_site_average_review_count * $set_site_average_review_score) + $total_quality) / ($set_site_average_review_count + $business_review_count);
$bayesian_service = (($set_site_average_review_count * $set_site_average_review_score) + $total_service) / ($set_site_average_review_count + $business_review_count);
$average_bayesian_rating = ($bayesian_value + $bayesian_quality + $bayesian_service) / 3;
$average_bayesian_rating = $average_bayesian_rating;
array_push($items, array(
"id"=>"$single_business_id",
"name"=>"$name",
"value"=>"$total_value",
"quality"=>"$total_quality",
"service"=>"$total_service",
"average"=>"$average_bayesian_rating"));
echo
'Name: '.$name.'<br>
Value: '.$total_value.'<br>
Quality: '.$total_quality.'<br>
Service: '.$total_service.'<br>
Average: '.$average_bayesian_rating.'<br><br>';
}
}
The page will be split up by a separate pagination script and will only display 6 objects at a time, but over time this may change so I do have an eye on performance as much as I can.
SQL aggregate queries are made for this kind of thing.
Use this query to summarize the results
SELECT b.name, b.id,
SUM(value) total_value,
SUM(quality) total_quality,
SUM(service) total_service,
COUNT(*) review_count,
avg_reviews_per_biz
FROM business b
JOIN ratings r ON b.id = r.business_id
JOIN (
SELECT COUNT(DISTINCT business_id) / COUNT(*) avg_reviews_per_biz
FROM ratings
) a ON 1=1
GROUP BY b.name, b.id, avg_review_per_biz
This will give you one row per business showing the summed ratings and the number of ratings. This result set will have the following columns
name business name
id business id
total_value sum of value ratings for that business
total_quality sum of quality ditto
total_service sum of service ditto
review_count number of reviews for business "id"
avg_reviews_per_biz avg number of reviews per business
The last column has the same value for all rows of your query.
You can then loop over these row one business at a time doing your statistical computations.
I can't tell from your question where you're getting variables like $set_site_average_review_count, so I can't help with those computations.
You'll find that SQL aggregate querying is very powerful indeed.

Taking long time executing complex mySql query

My query looks like this:
$result_portlist=mysql_query("
SELECT
portfolio AS the_port,
SUM(balance * course) AS the_balance,
SUM(insurance * course) AS the_insurance
FROM banks_all
WHERE CONCAT(balance, insurance)!='0'
GROUP BY portfolio
",$db);
$myrow_portlist=mysql_fetch_array($result_portlist);
if(mysql_num_rows($result_portlist)>0) {
do {
echo '<span> value1, vaule2, value3...</span>';
$result_portlist1=mysql_query("
SELECT
department AS the_department,
SUM(balance * course) AS the_balance,
SUM(insurance * course) AS the_insurance
FROM banks_all
WHERE CONCAT(balance, insurance)!='0'
AND portfolio='$myrow_portlist[the_port]'
GROUP BY department
",$db);
$myrow_portlist1=mysql_fetch_array($result_portlist1);
if (mysql_num_rows($result_portlist1)>0) {
do {
echo '<span> value1, vaule2, value3...</span>'
$result_portlist2=mysql_query("
SELECT
manager_name AS the_manager,
SUM(balance * course) AS the_balance,
SUM(insurance * course) AS the_insurance
FROM banks_all
WHERE CONCAT(balance, insurance)!='0'
AND portfolio='$myrow_portlist[the_port]'
AND department='$myrow_portlist1[the_department]'
GROUP BY manager_name
",$db);
{
do {
echo '<span> value1, vaule2, value3...</span>';
} while ($myrow_portlist2=mysql_fetch_array($result_portlist2));
}
} while ($myrow_portlist1=mysql_fetch_array($result_portlist1));
}
} while ($myrow_portlist1=mysql_fetch_array($result_portlist1));
}
So this query takes hours to execute for table with 40,000+ rows with hundreds of combinations of portfolio+department+manager_name. What I thought was to make one query at start that would group values by manager_name and then let php group portfolio and department. After creating this query, my mind has just blown up and has no free memory left to think :)
Please advice me how to rearrange this query or how to simplify it to take less time to execute.
Thanks in advance.
EDIT: here is image, how my table (with nested tables) look like:
IMAGE
The reason why it takes a lot of time is because you are executing a massive amount of queries... Let's say you have 10 portfolios, in 10 departments, you'd make 100 queries. This amount is insane, and reducing the number of queries is pretty simple in your case.
I would simply grab all the data in one query, and use a 3 level group by with a rollup:
$result=mysql_query("
SELECT
portfolio AS the_port,
department AS the_department,
manager_name AS the_manager,
SUM(balance * course) AS the_balance,
SUM(insurance * course) AS the_insurance
FROM banks_all
WHERE
CONCAT(balance, insurance)!='0'
GROUP BY
portfolio,
department,
manager_name
with ROLLUP
ORDER BY the_port,the_department,the_manager;
",$db);
echo '<table>';
while($row = mysql_fetch_assoc($result)){
if($row['the_port'] === null){
//This is the big total row... Let's skip it for now shall we?
continue;
}
echo '<tr>';
if($row['the_department'] === null){
echo '<td>Portfolio: '.$row['the_port'].'</td>';
}else{
if($row['the_manager'] === null){
echo '<td>Department: '.$row['the_port'].'</td>';
}else{
echo '<td>Manager: '.$row['the_port'].'</td>';
}
}
echo '<td>'.$row['the_balance'].'</td>';
echo '<td>'.$row['the_insurance'].'</td>';
echo '</tr>';
}
echo '</table>';
This query will return all lines grouped by portfolio then grouped by department, then grouped by manager. This would return all rows from the finest point (your third while) but with ROLLUP you will also get a row for the other group by levels. This is exactly as if you would have done GROUP BY portfolio,department and GROUP BY portfolio inside the same query.
In the rolled up rows, the value of the keys omitted from the group by will be NULL. So you can easily check on the_manager, when it's null it means you have the full department, when the_department is null you have the full portfolio.

Categories