MYSQL nested query running very slow? - mysql

The following query is constantly timing out, is there a less overhead way to achieve the same function ?
UPDATE Invoices SET ispaid = 0
WHERE Invoice_number IN (SELECT invoice_number
FROM payment_allocation
WHERE transactionID=305)
What I'm doing is unallocating invoices from a transaction, there can be up to 30+ records returned but it stops the database dead everytime I try to run it

USE JOIN instead of subquery it will improve the performance.
Create index on Invoice_number column in both table if you haven't created.
Try this:
UPDATE Invoices i
INNER JOIN payment_allocation pa ON i.Invoice_number = pa.invoice_number
SET i.ispaid = 0
WHERE pa.transactionID = 305;

I'd try EXISTS :
UPDATE Invoices a set ispaid=0
WHERE EXISTS
(
SELECT NULL FROM payment_allocation b
WHERE b.Invoice_number =a.Invoice_number AND b.transactionID=305
)

As of MySQL 5.5, Subquery Selects (another full select statement inside the query) cannot be optimized. This is probably why your query is so slow. Refactor you query to get rid of the inner select statement.
UPDATE Invoices, payment_allocation
SET ispaid=0
WHERE payment_allocation.transactionID=305 AND
Invoices.Invoice_number = payment_allocation.invoice_number
An interesting sidenote... But MariaDB (a branch of MySQL by the original creator) has implemented Subquery select optimization.

UPDATE invoices i
JOIN payment_allocation pa
ON pa.invoice_number = i.invoice_number
SET i.ispaid=0
WHERE pa.transactionID = 305;

Related

Any way to faster sql query containing IN clause where data for IN clause is obtained from with in a query?

During my project, I came across a requirement where I need to process some operation over some address which is not present inside some other table, and for that, I have written the following query. But I think this query will go slow when the entries in the second table 'transaction' increases.
select emp_address
from emp_leave_wallet
where attached ="mycompany_wallet" and
emp_address not in (select destination_address from transaction);
Any other way, other than adding Index over destination_address.
A solution using a JOIN but I can't quantify the performance gain:
SELECT ew.emp_address
FROM emp_leave_wallet ew
LEFT OUTER JOIN transaction t on
t.emp_address = ew.emp_address
WHERE ew.attached = "mycompany_wallet" and
t.emp_address IS NULL
I would start with not exists:
select lw.emp_address
from emp_leave_wallet lw
where lw.attached = 'mycompany_wallet' and
not exists (select 1
from destination_address da
where lw.emp_address = da.destination_address
);
Then for this query you definitely want an index on destination_address(destination_address) and probably on (attached, emp_address).
Use not exists :
select ew.emp_addres
from emp_leave_wallet ew
where ew.attached = "mycompany_wallet" and
not exists (select 1 from transaction t where t.destination_address = ew.emp_address);
Use NOT EXISTS which returns record if there is no matching row in transaction table based on where condition:
select emp_address
from emp_leave_wallet e
where attached = 'mycompany_wallter'
and not exists (
select 1
from transaction t
where e.emp_address = t.destination_address
)
Create indexes:
CREATE INDEX idx1 ON emp_leave_wallet(attached, emp_address);
CREATE INDEX idx2 ON transaction(destination_address);
select emp_address
from emp_leave_wallet
where attached ="mycompany_wallet" and
emp_address not in (select destination_address from transaction);
Your emp_leave_wallet and transaction table should have id fields (I'm guessing ... emp_id, transaction_id)
If it were me i would...
select emp_address
from emp_leave_wallet elw
inner join transaction t
on elw.emp_id = t.transacation_id

mysql update with data from another table with join on two fields

I need to update 1 table with data from another where two fields match. I have a query but it's just locking up.
I have an employees_training_courses table
I have a company_training_categories table
I need to get the ID from company_training_categories where both the name and the account_id are the same in both tables.
So far I have this...
update employee_training_courses tc join company_training_categories ctc on ctc.name = tc.name AND ctc.account_id = tc.account_id set tc.company_training_category_id = ctc.id;
i can leave the query running, but it's clearly getting hung up somewhere !
This is your query:
update employee_training_courses tc join
company_training_categories ctc
on ctc.name = tc.name AND ctc.account_id = tc.account_id
set tc.company_training_category_id = ctc.id;
This is a very reasonable query. You probably just need indexes to speed it up. I would recommend:
create index idx_company_training_categories_2 on company_training_categories(name, account_id)
or even:
create index idx_company_training_categories_3 on company_training_categories(name, account_id, id)

mySQL update a value

Modified some stuff from my pic so you guys can understand it
I have this database. I am trying to update a value from a table based on another value from an another table.
I want to update the SUM from salary like this :
( sum = presence * 5 )
This is what I've been trying to use ( unsuccessful )
update table salary
set suma.salary = users.presence * 5
FROM salary INNER JOIN users1 INNER JOIN presence on id_salary = id_presence
I am not sure what to do, I'd appreciate some help, Thanks
In MySQL to UPDATE tables with a join you use this syntax:
UPDATE table1, table2
SET table1.column = some expression
WHERE table1.column = table2.column
That said, even with the updated picture, in your SQL you are mentioning columns that I cannot understand in which table are to be found. You also have an inner join between salariu and users1, with no join condition. Could you please clean up the question and make everything clear?
Assuming you are making the updates to the db structure you were talking about, then you can start working on this one maybe:
UPDATE salary, presence
SET salary.sum = SUM(presence.hours) * 5
WHERE presence.id = salary.id
AND <some filter on the month that depends on salary.date>
Another way, but I'm not sure it is supported in all RDBMS, would be something like this:
UPDATE salary
SET sum = (
SELECT SUM(presence.hours) * 5
FROM user, presence
WHERE presence.id = salary.id
AND <some filter on the month that depends on salary.date>
)

Mysql, combining and querying results with sub queries or temp tables

I am running into some trouble with the following circumstances:
I have a query that creates two temp tables, and the following select to join them together--
SELECT * FROM result
INNER JOIN result2 ON result2.packetDetailsId = result.packetDetailsId
I am then trying to create another column from concatenating a few of the resulting fields and then use that to reference/query against another table. Is there a way to accomplish this in one query? Should I get away from the temp tables?
Thank you again in advance.
update: If I try to alias the combination of the two temp tables I get an error message stating [Err] 1060 - Duplicate column name 'packetDetailsId'
select * from (
SELECT * FROM result
INNER JOIN result2 ON result2.packetDetailsId = result.packetDetailsId) as myalias
Another Update: I almost have it working as one query but I get the result "(BLOB)" in the column I concoctenated:
select packet_details.packetDetailsId,products.productId,Credit,AccountNum,OrderStat, CONCAT(products.productId,Credit,'_',OrderStat) as consol from (
select packetDetailsId, GROUP_CONCAT(Credit) AS Credit, GROUP_CONCAT(AccountNum) AS AccountNum, GROUP_CONCAT(OrderStat) AS OrderStat FROM
( SELECT pd_extrafields.packetDetailsId,
CASE WHEN pd_extrafields.ex_title LIKE ('%Credit%')
THEN pd_extrafields.ex_value ELSE NULL END as Credit,
CASE WHEN pd_extrafields.ex_title LIKE ('%Account%')
THEN pd_extrafields.ex_value ELSE NULL END as AccountNum,
CASE WHEN pd_extrafields.ex_title LIKE ('%Existing%')
THEN pd_extrafields.ex_value ELSE NULL END as OrderStat
FROM pd_extrafields )AS TempTab GROUP BY packetDetailsId ) as alias2
INNER JOIN packet_details ON alias2.packetDetailsId = packet_details.packetDetailsId
INNER JOIN sales ON packet_details.packetDetailsId = sales.packetDetailsId
INNER JOIN sold_products ON sales.saleId = sold_products.saleId
INNER JOIN products ON sold_products.productId = products.productId
If I understand correctly, you already have the temporary tables created and you need to "concatenate" the results, using from ... inner join ...
The only possible restriction you may have is that you can only reference your temporary tables once in your from clause; besides that, there are no other restrictions (I frequently use temporary tables as intermediate steps in the creation of my final result).
Tips
Let's say your temp tables are temp_result1 and temp_result2. Both tables have a field packedDetailsId, on which the join will be performed. Remember to create the appropriate indexes on each table; at the very least you need to index packedDetailsId on both tables:
alter table temp_result1
add index PDI(packedDetailsId);
alter table temp_result2
add index PDI(packedDetailsId);
Now, just execute a query with the desired join and concatenation. If concat returns BLOB, then cast the result as char (of course, I'm assuming you need a text string):
select r1.*, r2.*, cast(concat(r1.field1, ',', r2.field2) as char) as data_concat
from temp_result1 as r1
inner join temp_result2 as r2 on r1.packedDetailsId = r2.packedDetailsId;
I see your problem is that GROUP_CONCAT is returning BLOB values... It's normal (MySQL doesn't know a priori how to return the values, so it returns binary data); just use the cast function.
Hope this helps you
so, if the result2 and result are both temp tables, you will have to include the # if local temp table and ## if global temp table
so your statements should be :
SELECT * FROM #result
INNER JOIN #result2 ON #result2.packetDetailsId = #result.packetDetailsId
My Bad. This is only applicable for MS SQL

subquery in where clause of UPDATE statement

I have the database of ATM card in which there are fields account_no,card_no,is_blocked,is_activated,issue_date
Fields account number and card numbers are not unique as old card will be expired and marked as is_block=Y and another record with same card number ,account number will be inserted into new row with is_blocked=N . Now i need to update is_blocked/is_activated with help of issue_date i.e
UPDATE card_info set is_blocked='Y' where card_no='6396163270002509'
AND opening_date=(SELECT MAX(opening_date) FROM card_info WHERE card_no='6396163270002509')
but is doesn't allow me to do so
it throws following error
1093 - You can't specify target table 'card_info' for update in FROM clause
Try this instead:
UPDATE card_info ci
INNER JOIN
(
SELECT card_no, MAX(opening_date) MaxOpeningDate
FROM card_info
GROUP BY card_no
) cm ON ci.card_no = cm.card_no AND ci.opening_date = cm.MaxOpeningDate
SET ci.is_blocked='Y'
WHERE ci.card_no = '6396163270002509'
That's one of those stupid limitations of the MySQL parser. The usual way to solve this is to use a JOIN query as Mahmoud has shown.
The (at least to me) surprising part is that it really seems a parser problem, not a problem of the engine itself because if you wrap the sub-select into a derived table, this does work:
UPDATE card_info
SET is_blocked='Y'
WHERE card_no = '6396163270002509'
AND opening_date = ( select max_date
from (
SELECT MAX(opening_date) as_max_date
FROM card_info
WHERE card_no='6396163270002509') t
)