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.
Related
I have a problem i hope you can help me out with.
To break it down, i have a table in the database where i create events, it's called "dansetimer" and for that i have a table called for the participants on the events, called "transak"
I want to count how many events within a given time, had more than 20 participants.
I have made this for a start, and it's also very good, but i cant see how to count, how many events i end up with, of course i can just count the list manually, but i really want to get PHP to count it.
$hentgg = mysql_query("SELECT * FROM dansetimer WHERE dato BETWEEN $fra AND $til");
if(mysql_num_rows($hentgg)) {
while($visgg = mysql_fetch_array($hentgg)) {
$result=mysql_query("SELECT count(*) as total FROM transak WHERE produkt = '$visgg[id]'");
$data=mysql_fetch_assoc($result);
if($data['total'] > 20) {
echo $visgg[title];
}
}
} else {
echo "Ingen resultater";
}
With the above code i'm able to retrieve the events and get them listed.
With this code:
$result=mysql_query("SELECT count(*) as total FROM transak WHERE produkt = '$visgg[id]'");
$data=mysql_fetch_assoc($result);
I can count how many participants there are on the event, and with the if statement, testing if there are more than 20, i can hide the events, that dont have more participants.
But do you have a great idea for how i can write "Within the given time, you held 23 events with more than 20 participants" or something like that.
You could keep an extra counter in the loop, so you can see how many events have over 20 participants:
// At the start of your script
$large_events = 0;
...
// In your loop:
if($data['total'] > 20) {
echo $visgg[title];
$large_events++;
}
But I think it's easier, and probably faster too, to let SQL give you already some more details. In your solution it will query the participants for each event, so if someone has 1000 events, each with 20 participants or less, your database has to do 1001 queries, end the end result is 'Ingen resultater'.
So, change the query to this:
SELECT *
FROM
( SELECT
dt.*,
(SELECT count(*) FROM transak WHERE produkt = dt.id) AS total_participants
FROM dansetimer dt
WHERE dato BETWEEN $fra AND $til
)
WHERE
total_participants > 20
ORDER BY
dato,
title
This query returns only events with more than 20 participant, and it will return the number of participants per event. So you can just fetch this query result into a simple array and display each item to show the title, number of participants and other information. And the length of the array is the number of 'large' events.
PS: Did you know that the mysql_* functions are old and are removed in PHP 7? I think it's time for an upgrade to PDO.
Need to use this below query and you will get desired output (I want to count how many events within a given time, had more than 20 participants.).
SELECT count(*) FROM dansetimer dt WHERE (SELECT count(*) FROM transak WHERE produkt = dt.id)>=20 and dato BETWEEN $fra AND $til
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.
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).
Ok, so right now i have a query inside of the while loop from another query...but there's got to be a more efficient way of doing what i'm trying to do. Can i accomplish the below script via one query? And would that be more efficient? (i'm assuming it would be) Here's what i have now (not the real code, but a good example):
$sth = $dbh->prepare("SELECT * FROM Bugs LIMIT 5");
$sth->setFetchMode(PDO::FETCH_OBJ);
$sth->execute();
while($row = $sth->fetch()){
$bugId = $row->id;
echo 'Bug Name: ' . $row->name;
echo '<br />';
echo 'Affected Web Browsers: ';
$sth2 = $dbh->prepare("SELECT * FROM AffectedBrowsers WHERE BugId = '$bugId'");
$sth2->setFetchMode(PDO::FETCH_OBJ);
$sth2->execute();
$i = 1;
while($row2 = $sth2->fetch()){
if($i = 1){
echo $row2->browser;
}else{
echo ', ' . $row2->browser;
}
$i++;
}
}
My tables are as follows:
1) "Bugs" - this table has one row for each bug listed.
2) "AFfectedBrowsers" - this table houses all of the affected browsers for a particular bug. This table has a relationship with the "Bugs" table via the bugId column in the "AffectedBrowsers" table.
Note: I do realize that incrementing the $i could be done in a for loop instead of an if/else.
UPDATED: I need just one row per bug and i'm guessing add a column in the result set that has all of the affected browsers for that bug listed.
SELECT * FROM Bugs
INNER JOIN AffectedBrowsers ON Bugs.Id = AffectedBrowsers.BugId
LIMIT 5
Is that what your looking for?
SELECT * FROM Bugs
LEFT JOIN AffectedBrowsers
ON Bugs.BugId = AffectedBrowsers.BugId
LIMIT 5
If you want to list bugs, even if there are no affected browsers. By the way, you should get into the habit of listing out what columns you wan't to retrieve data from.
SELECT *
FROM Bugs
INNER JOIN
(SELECT BugId, GROUP_CONCAT(Browser) Browsers FROM AffectedBrowsers GROUP BY BugId) Aff
ON Bugs.Id = Aff.BugId
The other answers are good. However, if you need to limit the number of bugs and don't care about the number of affected browsers, use this:
SELECT *
FROM AffectedBrowsers
WHERE BugID IN ( SELECT id FROM Bugs LIMIT 5 )
Note that this is a real subquery. But, unlike your code, it is contained in one single statement and should still be faster.
I'm coding in PHP/MySQL and have the following query to fetch products and product group data:
SELECT products.id,products.name,product_groups.id,product_groups.name
FROM products
INNER JOIN product_groups
ON products.id=product_groups.id
WHERE products.name LIKE '%foobar%'
ORDER by product_groups.id ASC
So this query fetches products and orders them by product group. What I would like to have is to display product_groups.name just once for each product grouping. So even if I have ten shoe products, the group name "Shoes" is only displayed once.
I'm using the following PHP to print out the results:
while ($data = mysql_fetch_array($result))
If you want it done in the MySQL query, it is honestly more trouble than it's worth. For one, the syntax is really wonky (as I recall) to have a group name listed at the top of each grouping. And the results are still treated as rows, so the group name will be treated like a row with all the other columns as Null, so you won't really save any time or effort in the PHP script as it has to do an if statement to catch when it hits a group name instead of the group data.
If you want it done by the PHP while loop, Johan is on the right track. I use the following for a similar situation:
$result = $sql->query($query);
$prev_group = "";
while($data = $result->fetch_assoc()){
$curr_group = $data['group'];
if ($curr_group !== $prev_group) {
echo "<h1>$curr_group</h1>";
$prev_group = $curr_group;
}
else {
echo $data;
.....
}
Obviously the echo data would be set up to echo the parts of the data the way you want. But the $prev_group/$curr_group is set up so that the only time they won't match is when you are on a new group and thus want to print a header of some sort.
while($data = mysql_fetch_assoc($result)){
if($data['product_groups.name'] != $groupname){
echo "Groupname: ".$data['product_groups.name']."<br />";
$groupname = $data['product_groups.name'];
}
echo "ID: ".$data['products.id']."<br />";
echo "Name: ".$data['products.name']."<br />";
}
Maybe you can do like this!?