I have a problem about my code, this is my code on connecting to database, selecting some unique data and sum on these unique data from another table, nothing problem with my code, thats all okay, but it taking so long time on querying.
<?php
include "koneksi.php";
$no=1;
$arqury=odbc_exec($koneksi, "SELECT DISTINCT NIP_AR,NAMA_AR FROM USRBPS.MASTERFILE");
while($ar=odbc_fetch_array($arqury)){
$total=0;
$ambilqury=odbc_exec($koneksi, "SELECT NPWP FROM USRBPS.MASTERFILE WHERE NIP_AR='$ar[NIP_AR]'");
while($ambil=odbc_fetch_array($ambilqury)){
$testqury=mysql_query("SELECT SUM(jumlah_bayar) as PENERIMAAN FROM mpnruteng WHERE npwp='$ambil[NPWP]'");
$test=mysql_fetch_array($testqury);
$total += $test[PENERIMAAN];
}
if($ar[NIP_AR]==""){
echo "<tr><td>$no</td><td colspan=2>UNASSIGN</td><td>$total</td>";
}
else{
echo "<tr><td>$no</td><td>$ar[NAMA_AR]</td><td>$ar[NIP_AR]</td><td>$total</td></tr>";
}
$no++;
}
?>
on simply is being like this,
|Name |num_se
---------------
|andre |1111
|john |2222
|simon |3333
|andre |4444
|andre |5555
|simon |6666
|john |7777
|num_se |Total
---------------
|1111 |12
|2222 |15
|3333 |10
|4444 |8
|5555 |20
|6666 |18
|7777 |22
So, what i need is get the sum of 'Total', from each 'Name'. What i want to get is, list of the name "Uniquely" (in this example is Andre, John, and Simon) with each sum of "Total" that get from num_se.
sorry my english is bad, but i hope you're understand.
It would have been pertinent to explain you were working against two separate data sources up front.
It's slow because you're attempting to loop over your resultsets in PHP, calling individual queries to return single rows from another table, which is very inefficient.
Let the database handle the relationship between your two related tables by using a JOIN , and then let it handle to aggregation of your grand total, not just the individual totals.
The following query will get your total for each distinct pair of nip_ar and nama_ar:
SELECT
t1.NIP_AR,
t1.NAMA_AR,
SUM(t2.jumlah_bayar) as PENERIMAAN
FROM
USRBPS.MASTERFILE t1
INNER JOIN mpnruteng t2
ON t2.npwp = t1.npwp
GROUP BY
1, 2
But you're rolling this up into one grand $total anyhow, so this will get that for you:
SELECT
SUM(PENERIMAAN) as PENERIMAAN
FROM
(
SELECT
t1.NIP_AR,
t1.NAMA_AR,
SUM(t2.jumlah_bayar) as PENERIMAAN
FROM
USRBPS.MASTERFILE t1
INNER JOIN mpnruteng t2
ON t2.npwp = t1.npwp
GROUP BY
1, 2
)
You can configure a link to your mySql server from your Oracles server. Refer to Using Heterogenous Service Agents - chapter 4. Setting up access to non-Oracle systems. My understanding is that you cannot link to Oracle from mySql.
This will allow you to run the above queries, on your Oracle instance. Although you'll need to update your table names to fully qualify them with the datasource names.
If I understand correctly, this query may help
SELECT t1.Name, sum(t2.Total)
FROM (table1 t1 LEFT JOIN table2 t2 ON t1.num_se = t2.num_se)
GROUP BY t1.Name
Modify the table name and column name based on your case.
Update
I don't know why you use two separated data source. However, I think this approaches will improve the efficiency of your code.
First, get the list of all num_se belong to each name by this query:
"SELECT Name, GROUP_CONCAT(num_se) as nums FROM table1 GROUP BY Name"
Now your result array ('$ar') will have an element like this "1111,2222" with the key nums
Second, use this query to get the sum for each name
"SELECT SUM(Total) as total FROM Table2 WHERE num_se IN (" . $ar['nums'] . ")"
And you will get the total for each name without needing a second loop.
Remember to use escaping techniques to be sure your queries is safe.
If you're on Windows, I have noticed that using localhost instead of 127.0.0.1 slows down the connection to the database.
Before giving any solution I wanted to share the reason why your query is too slow. If you see your code carefully you are opening database connection for reach record in the first query result. The major cost is going in opening and running the query against the database . SO imagine if you have 1000 records in the first result , you will open the database connection 1000 times , that will make it very very slow. Use the Inner join or subquery as stated by Trung . Or if not possible using stored procedure and putting the logic inside the SP will also help you to gain the performance.Create a Stored procedure and pass the input parameter as comma separated Ids what you are getting from another database , Inside the SP use the comma separated Ids to either loop and do the select statement. You can use the temp table to do so. The advantage is that you will open the Database connection only once.
Related
i want to fetch records from mysql starting from last to first LIMIT 20. my database have over 1M records. I am aware of order by. but from my understanding when using order by its taking forever to load 20 records i have no freaking idea. but i think mysql fetch all the records before ordering.
SELECT bookings.created_at, bookings.total_amount,
passengers.name, passengers.id_number, payments.amount,
passengers.ticket_no,bookings.phone,bookings.source,
bookings.destination,bookings.date_of_travel FROM bookings
INNER JOIN passengers ON bookings.booking_id = passengers.booking_id
INNER JOIN payments on payments.booking_id = bookings.booking_id
ORDER BY bookings.booking_id DESC LIMIT 10
I suppose if you execute the query without the order by the time would be satisfactory?
You might try to create an index in the column your are ordering:
create index idx_bookings_booking_id on bookings(booking_id)
You can try to find out complexity of the Query using
EXPLAIN SELECT bookings.created_at, bookings.total_amount,
passengers.name, passengers.id_number, payments.amount,
passengers.ticket_no,bookings.phone,bookings.source,
bookings.destination,bookings.date_of_travel FROM bookings
INNER JOIN passengers ON bookings.booking_id = passengers.booking_id
INNER JOIN payments on payments.booking_id = bookings.booking_id
ORDER BY bookings.booking_id DESC LIMIT 10
then check the proper index has been created on the table
SHOW INDEX FROM `db_name`.`table_name`;
if the index us not there create proper index on all the table
please add if anything is missing
The index lookup table needs to be able to reside in memory, if I'm not mistaken (filesort is much slower than in-mem lookup).
Use small index / column size
For a double in capacity use UNSIGNED columns if you need no negative values..
Tune sort_buffer_size and read_rnd_buffer_size (maybe better on connection level, not global)
See https://dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html , particularly regarding using EXPLAIN and the maybe trying another execution plan strategy.
You seem to need another workaround like materialized views.
Tell me if this sounds like it:
Create another table like the booking table e.g. CREATE TABLE booking_short LIKE booking. Though you only need the booking_id column
And check your code for where exactly you create booking orders, e.g. where you first insert into booking. SELECT COUNT(*) FROM booking_short. If it is >20, delete the first record. Insert the new booking_id.
You can select the ID and join from there before joining for more details with the rest of the tables.
You won't need limit or sorting.
Of course, this needs heavy documentation to avoid maintenance problems.
Either that or https://stackoverflow.com/a/5912827/6288442
I have two tables-
1) ****Company_Form****
[Contract_No#,Software_Name,Company_Name,Vendor_Code]
2) ****User_Form****
[Contract_No,Invoice_No#,Invoice_Date,Invoice_Amount,Invoice_Submit_Date]
Fields denoted with # and bold are primary keys.
=>The user has to enter a software name for which he wants to get the data of.
=>I have to structure a query in which I have to display the result in the following form:
[Contract#,Software_Name,Company_Name,Invoice_No,Invoice_Date,Invoice_Submission_Date]
Now,
one Contract_No can contain many Invoice_no under its name in
the User Form table.
One Contract_No can occur one time only in
Company_Form table
The retrieved records have to be group by the latest Invoice_Date
I came to the logic that:
I have to first retrieve all the contract numbers with that software
name from Company_Form table.
I have to query that contract number from User_Form table and display
the data for each matched contract no. fetched from Company_Form
table.
The problem is that I am unable to structure a query in SQL that can do the task for me.
Kindly help me in formulating the query.
[PS] I am using SQL with PHP.
I tried a query like:
I tried one approach as :
SELECT a.ContractNo,a.SoftwareName,a.CompanyName,b.InvoiceNo,b.InvoiceDate,b.InvAmount,b.InvoiceSubmitDate
FROM Company_Form as a,User_Form as b
WHERE b.ContractNo IN(SELECT ContractNo FROM Company_Form WHERE
SoftwareName='$Sname') AND a.ContractNo=b.ContractNo;
But I am getting a error that sub query returns more than 1 row.
Can I get help from this?
I am assuming you are attempting to find the most recent price of the user selected software and its corresponding invoice. Here is an approach to do this. If this is tested to your satisfaction, I can add necessary explanation.
select uf.Contract_No#,
cf.Software_Name,
cf.Company_Name,
uf.Invoice_No#,
uf.Invoice_Date,
uf.Invoice_Amount,
uf.Invoice_Submit_Date
from User_Form uf
inner join (
-- Most recent sale of software
select Contract_No#, max(Invoice_Date)
from User_Form
group by Contract_No#
) latest
on (
-- Filter via join for latest match records
uf.Contract_No# = latest.Contract_No#
and uf.Invoice_Date = latest.Invoice_Date
)
inner join Company_Form cf
on cf.Contract_No# = uf.Contract_No#
where cf.Software_name = :software_name
If the requirement allows your sub query to return more than one row, I would suggest you to use IN instead of = in the where clause of your main query.
Please note that I have just looked at the query and have not fully understood the requirements.
Thanks.
I worked around for some time and finally came to the following query which works like a charm
SELECT a.ContractNo,a.SoftwareName,a.CompanyName,b.InvoiceNo,b.InvoiceDate,b.InvAmount,b.ISD
FROM Company_Form as a,User_Form as b
WHERE b.ContractNo IN (SELECT ContractNo FROM Company_Form WHERE SoftwareName='$Sname')
AND a.ContractNo=b.ContractNo;
If anybody needs help in understanding the logic of this query,feel free to comment below.
This question is not to discuss if the setup of the DB is as it should be, i'm not happy with how it is, but it is how it is and a refactor will not be done by the DBA at this moment.
What i am looking for is a way to join a table, for which i do not in advance know the table name but it is in the table i want to do the join against.
So:
TABEL transactions
trans_id autherizer
001Bar payment_provider_a
001Foo payment_provider_b
TABLE payment_provider_a
trans_id amount
001Bar 50
TABLE payment_provider_b
trans_id amount
001Foo 50
The table names are fictional, but the setup is identical. There is a transaction table, which stores an transaction_id and a payment_provider string name (with a lot of additional data, which is not relevant for the question).
Would there be anyway to get all the data from the transaction table and in that query do directly a join on the payment_provider table, for which we only now what that table can be from the transaction table.
I have tagged it with PHP as well, since i want to make the call with PDO. Whole PHP snippets are not required, but if you insist ;). A push in the right direction for the query it self would be sufficient. I am aware that i am lacking the example of what i have tried. But to be honest i haven't tried that much because i can't really think of something, it's the first time i am in this kind of need for such a query.
Not overly clean, but you can try this:
SELECT * FROM transactions t JOIN
(
SELECT 'payment_provider_a' AS name,* FROM payment_provider_a
UNION
SELECT 'payment_provider_b' AS name,* FROM payment_provider_b
) p ON t.payment_provider = p.name AND t.trans_id=p.trans_id
Note that all payment_provider_x tables must have the same number and types of columns. Otherwise you'll need to select only the fields that are actually common (there are ways around this if needed).
Is it ok to a mysql query inside a while loop using the ID of each row passed to fetch results from another table? OR is there a better way to do it?
$q = $__FROG_CONN__->query("SELECT cms_page.id, cms_page.title, cms_page.slug, cms_page_part.* FROM cms_page LEFT JOIN cms_page_part ON cms_page_part.page_id=cms_page.id WHERE cms_page.parent_id='8'");
$r = $q->fetchAll(PDO::FETCH_ASSOC);
echo '<ul id="project-list">';
foreach ($r as $row) {
echo '<li>';
echo '<img src="<img src="phpThumb/phpThumb.php?src=public/images/'.$row[0].'/th.jpg&w=162" alt="" />';
echo '<div class="p-text">';
echo '<h4>'.$row["location"].'<span>'.$row["project_date"].'</span></h4>';
echo '<p>'.$row["body"].'</p>';
echo '</div>';
echo '</li>';
}
echo '</ul>';
I am trying to pull the project_date, body and location fields from another table where the sql query matches. The title and slug are held in another table. There should only be a maximum of eight or so results but im getting alot more.
The suggestions using IN are fine, but if you are getting the ids from another query, it might be better to combine these two queries into one query using a join.
Instead of:
SELECT id FROM users WHERE age <30
SELECT id, x FROM userinfo WHERE userid IN ($id1, $id2, ..., $idn)
do:
SELECT users.id, userinfo.x
FROM users
LEFT JOIN userinfo ON userinfo.userid = users.id
WHERE age < 30
To reduce the overhead of preforming a query, you may want to look at getting all the data in a single query. In which case you may want to take a look at IN(), e.g.
SELECT * WHERE x IN (1, 2);
There is also BETWEEN()
SELECT * WHERE x BETWEEN 1 AND 2;
See the mysql docs for more information
I would try to build the query in a way where I only need to pass it once. Something like WHERE ID=1 OR ID=2 OR ... Passing multiple queries and returning multiple recordsets is expensive in terms of processing and network traffic.
This will be very inefficient, what you want is to join the tables on the ID
SELECT * FROM table1 LEFT JOIN table2 ON (table1.ID = table2.ID) WHERE condition
Mysql join documentation
This will return one set of rows with all the information you need, returned from both tables.
In a small application / small result set, this might be okay, but it results in a lot of (small) calls to the database.
If you can find an alternative way (perhaps see Yacoby's suggestion?) in which you can do one call to the database, this is probably better.
EDIT
If you are only interested in the IDs from one table, in order to get the correct results out of another table, perhaps a JOIN is what you are looking for?
SELECT t1.fieldA, t1.fieldB
FROM table1 t1
JOIN table2 t2 ON t1.ID = t2.ID
WHERE t2.someField = 'someValue'
Is it ok to a mysql query inside a while loop using the ID of each row passed to fetch results from another table? OR is there a better way to do it?
You should reformulate your query in SQL. Say, put the ids into a memory table and use it in a JOIN:
SELECT *
FROM idtable
JOIN mytable
ON mytable.id = idtable.id
This way, MySQL will make the loops for you but will make them in (usually) more efficient way.
SQL is a language designed to work with sets.
So if you have a set of ids and a table (which is a set of tuples), your first thought should be "how do I apply the set-based operations to these sets using SQL"?
Of course it is possible to run a bunch of simple queries in a loop but this way you just do extra work which SQL engine developers most probably have already done for you (and usually have done it in more efficient way).
You may want to read this article in my blog:
Double-thinking in SQL
If you had data in table 1 that you need to use to return data in table 2 for each row returned in table 1. What is more efficient to use a set of querys in PHP one inbedded in the while loop of the other or an SQL function within a query?
for example:
$qry = mysql_query(SELECT date FROM table1)
while($res = mysql_fetch_array($qry))
{
$qry = mysql_query("SELECT name FROM table2 WHERE date=$res['date']")
}
or to do this as a function that returns the Id from table1 within the query.
A (LEFT / RIGHT) JOIN?
Unless I've misunderstood the question...
I think you're looking for JOIN sql syntax. If you have 2 tables: messages and author and you want to return messages with authors. Then you can write following SQL statement:
SELECT m.body, a.name FROM message m
LEFT JOIN author a ON (a.id=m.author_id)
This will return message body with corresponding author name
Table author:
id - primary key
name - name of the author
Table message:
body - text of the message
author_id - id of the author
UPD1:
This will be faster then looping each message and select an author. Because JOIN allows you to return all data in single query (not N x queries when using for loop).
UPD2:
With your tables the query will look like:
SELECT t1.date, t2.name FROM table1 t1 LEFT JOIN table2 t2 ON (t2.date=t1.date)
It depends on if the data is easier to find during the while loop or in the query itself.
So if the DB has to base the sub-query on the result of each row in the main query, and there are 1000 total rows and 100 results in the main query, it has to check all of the rows 100 times, so that's 100,000 sub-queries it runs.
So think it terms of the number of results of the main query. If your while loop has to query the DB 100 times while the DB can do it much faster and efficiently in one query, that's better. But if you want a subset of answers that you can say 'query only based on the last set of results' the while loop is better.
What is more efficient to use
a set of querys in PHP one inbedded in the while loop of the other
or
an SQL function within a query
Seems you answered your question yourself, didn't you?
Every query you send to the dbms has to be sent over the network, parsed, analyzed then executed. You may want to minimize the number of queries sent to the db.
There may be exceptions, for example if the processing of the data requires operations which the dbms is not capable of.