Why left join takes so much time in MySQL? - mysql

I have created two temporary tables:
create temporary table temp.PromoCust (
CustId int(10)
);
create temporary table temp.Inv (
CustId int(10),
InvId int(10)
);
Insert some data:
insert into temp.PromoCust
select pl.CustomerId
from promoline pl
where pl.PromoId = 3008;
select * from temp.PromoCust; -- count is 234.995 customers
insert into temp.Inv
select i.CustomerId, i.InvoiceId
from invoice i
where i.InvoiceDate between '2016-12-21' and '2017-01-03';
select * from temp.Inv; -- count is 86.684 customers and invoices
And finally I run a left join query:
select pc.CustId, i.InvId
from temp.PromoCust pc left join temp.Inv i
on pc.CustId = i.CustId;
For some reason this takes forever. Is it something wrong with the query? I cannot really get any results from this.

Related

ERROR : Single-row subquery returns more than one row. I am trying to add data in column

I created a temp table and want to insert values in the table using select statements but when I run this query I am getting the above error. Is there any efficient way.
DROP TABLE IF EXISTS MANAGER_DATA;
CREATE TEMPORARY TABLE MANAGER_DATA (
WORKER_ID VARCHAR, ACCOUNT VARCHAR,
ACTIVE Boolean, REPORTING_NAME VARCHAR,
BUSINESS_TITLE VARCHAR, MANAGER_WORKER_ID VARCHAR,
MANAGER_REPORTING_NAME Text, MANAGER_OF_MANAGER_ID VARCHAR,
MANAGER_OF_MANAGER_NAME VARCHAR);
INSERT INTO MANAGER_DATA (
SELECT WORKER_ID,
ACCOUNT,
ACTIVE,
REPORTING_NAME,
BUSINESS_TITLE,
MANAGER_WORKER_ID,
(
SELECT
A.REPORTING_NAME
FROM ALL_ASSOCIATES_V AS A
INNER JOIN ALL_ASSOCIATES_V AS B
ON A.MANAGER_WORKER_ID = B.WORKER_ID),
(
SELECT B.MANAGER_WORKER_ID
FROM ALL_ASSOCIATES_V AS A
INNER JOIN ALL_ASSOCIATES_V AS B
ON A.MANAGER_WORKER_ID = B.WORKER_ID),
NULL
FROM ALL_ASSOCIATES_V
);
SELECT * FROM MANAGER_DATA;

Insert if exists

I have two tables: second table have foreign key, that references primary key of the first table. And when I insert data in the second table, I want to check first, if a row with iputed key exists in the first table. In T-SQL it would look like this:
create procedure insert_order_products
# order_id int
# product_id int
AS
IF EXISTS (SELECT * FROM order where order.id=order_id)
IF EXISTS (SELECT * FROM product where product.id=product_id)
INSERT INTO order_products values(some values)
How to check IF EXISTS in mysql?
I think you can try to use the following query (INSERT with SELECT and WHERE)
INSERT order_products(col1,col2,...,colN)
SELECT #val1,#val2,...,#valN
WHERE EXISTS(SELECT * FROM order WHERE id=#order_id)
AND EXISTS(SELECT * FROM product WHERE id=#product_id)
In MySQL I think it'll be like following
INSERT order_products(col1,col2,...,colN)
SELECT #val1,#val2,...,#valN
FROM DUAL
WHERE EXISTS(SELECT * FROM order WHERE id=#order_id)
AND EXISTS(SELECT * FROM product WHERE id=#product_id)
Or you can use
INSERT order_products(col1,col2,...,colN)
SELECT #val1,#val2,...,#valN
FROM (SELECT * FROM order WHERE id=#order_id) o
CROSS JOIN (SELECT * FROM product WHERE id=#product_id) p
I think the last variant is better.

Improve query of getting row with max value

I have next tables:
CREATE TABLE IF NOT EXISTS `Customers` (
`id` INT AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
PRIMARY KEY(`id`)
);
CREATE TABLE IF NOT EXISTS `Orders` (
`id` INT AUTO_INCREMENT,
`id_cust` INT NOT NULL,
`descr` VARCHAR(40),
`price` INT NOT NULL,
PRIMARY KEY(`id`),
FOREIGN KEY(`id_cust`) REFERENCES `Customers`(`id`)
);
One customer can have many orders. I want to get id_cust and sum of the orders of who paid the most(one person).
My query:
SELECT cust, max_orders_sum
FROM
(
(
SELECT MAX(orders_sum) AS max_orders_sum
FROM (
SELECT o.id_cust AS cust, SUM(o.price) AS orders_sum
FROM Orders AS o
GROUP BY o.id_cust
) AS same_query0
) AS step1
INNER JOIN
(
SELECT o.id_cust AS cust, SUM(o.price) AS orders_sum
FROM Orders AS o
GROUP BY o.id_cust
) AS same_query1
ON (step1.max_orders_sum = same_query1.orders_sum)
);
Main problem:
as you can see, it has the same parts: same_query0 and same_query1. Is there any way to get rid of them?
Or if you know the better way to reach my goal, please share.
I found one simple solution:
SELECT o.id_cust AS cust, SUM(o.price) AS orders_sum
FROM Orders AS o
GROUP BY o.id_cust
ORDER BY orders_sum DESC LIMIT 1;
But this is not a direct way to solve the problem.
I don't think you can do much better than what you've already done, unless you create a view like
create view v_cust_tot as
select id_cust, sum(price) as cust_tot
from Orders
group by id_cust
With that you'd be able to rewrite your query like this
select id_cust, cust_tot
from v_cust_tot
where cust_tot = (select max(cust_tot) from v_cust_tot)
This would be an improvement just in the compactness of the query, because I think performances would be the same as the execution plan would be almost identical
Another one nice solution:
select id_cust, sum(price) from orders group by id_cust having sum(price) =
(select max(prc) from
(select sum(price) as prc from orders group by id_cust) as tb);

Perform a INSERT .. SELECT in MySQL with derived tables

I'm trying to insert the results from a join query into another table.
INSERT INTO temp(
SELECT b.id, b.number, b.attempt FROM(
SELECT number FROM duplicate_numbers)a
JOIN calls b ON b.number=a.number));
The join query on its own without the INSERT INTO clause works fine and returns a dataset. But the above query gives SQL syntax error
Change query syntax like this:
CREATE TABLE temp (`id` int, `number` int, `attempt` int);
INSERT INTO temp (`id`, `number`, `attempt`)
SELECT b.id, b.number, b.attempt FROM (
SELECT number FROM duplicate_numbers
) a
JOIN calls b ON b.number=a.number
Working demo: http://sqlfiddle.com/#!9/24f9f

mysql insert multi row query result into table

I came across a scenario where I need to "upgrade" a table with data I obtain from another query. I am adding missing values so I will need to insert, but I cant seem to get it right.
The destination table is the following
CREATE TABLE `documentcounters` (
`UID` int,
`DataChar`,
`SeqNum` ,
`LastSignature`,
`DocumentType`,
`SalesTerminal`,
`Active`,
PRIMARY KEY (`UID`)
) ENGINE=InnoDB
and I am trying to do something like
INSERT INTO documentcounters
SELECT Q1.in_headers, -1,NULL, 17,0,0 FROM
(SELECT DISTINCT(DocumentSeries) as in_headers FROM transactionsheaders )AS Q1
LEFT JOIN
(SELECT DISTINCT(DataChar) as in_counters FROM documentcounters)AS Q2
ON Q1.in_headers=Q2.in_counters WHERE Q2.in_counters IS NULL;
I left UID out because I want the insert statement to create it, but I get a "Column count doesn't match" which makes sense (darn!)
Doing something like
INSERT INTO `documentcounters`
(`DataChar`,`SeqNum`,`LastSignature`,`DocumentType`,`SalesTerminal`,`Active`)
VALUES
(
(SELECT Q1.in_headers FROM
(SELECT DISTINCT(DocumentSeries) as in_headers FROM transactionsheaders )AS Q1
LEFT JOIN
(SELECT DISTINCT(DataChar) as in_counters FROM documentcounters)AS Q2
ON Q1.in_headers=Q2.in_counters WHERE Q2.in_counters IS NULL),-1,NULL,17,0,0
);
yields a "Subquery returns more than 1 row" error.
Any ideas how I can make this work?
Cheers
INSERT INTO `documentcounters`
(`DataChar`,`SeqNum`,`LastSignature`,`DocumentType`,`SalesTerminal`,`Active`)
SELECT Q1.in_headers, -1,NULL, 17,0,0 FROM
(SELECT DISTINCT(DocumentSeries) as in_headers FROM transactionsheaders )AS Q1
LEFT JOIN
(SELECT DISTINCT(DataChar) as in_counters FROM documentcounters)AS Q2
ON Q1.in_headers=Q2.in_counters WHERE Q2.in_counters IS NULL;
This will work if UID is defined as auto_increment.
If you want the INSERT to create the UID values, then UID must be defined as an auto-incrementing column.
CREATE TABLE `documentcounters` (
`UID` INT NOT NULL AUTO_INCREMENT,
...