SQL multiple left join as new columns performance - mysql

I have 3 tables :
account
id
name
1
Google
2
Apple
custom_field
id
name
1
Phone
2
Email
custom_field_submission
id
custom_field_id
entity_id
value
1
1
1
555-444-333
2
1
2
111-111-111
3
2
1
google#goog.com
4
2
2
apple#apple.com
Expected result after query
id
name
Phone
Email
1
Google
555-444-333
google#goog.com
2
Apple
111-111-111
apple#apple.com
I have a query like this :
SELECT
a.id,
a.name,
phone.value as phone,
email.value as email
FROM account a
LEFT JOIN (
SELECT DISTINCT custom_field_submission.value, custom_field_submission.entity_id
FROM custom_field_submission
WHERE custom_field_submission.custom_field_id = 1) AS phone
ON phone.entity_id = a.id
LEFT JOIN (
SELECT DISTINCT custom_field_submission.value, custom_field_submission.entity_id
FROM custom_field_submission
WHERE custom_field_submission.custom_field_id = 2) AS email
ON email.entity_id = a.id
In the reality I have 20 custom fields for 10 000 accounts. Where I run the query It is very slow (3-4 seconds)
Do you have an idea to manage optimize this ?
Thanks.

What you need here is a pivot query:
SELECT
a.id,
a.name,
MAX(CASE WHEN cf.name = 'Phone' THEN cfs.value END) AS Phone,
MAX(CASE WHEN cf.name = 'Email' THEN cfs.value END) AS Email
FROM account a
LEFT JOIN custom_field_submission cfs
ON cfs.entity_id = a.id
LEFT JOIN custom_field cf
ON cf.id = cfs.custom_field_id
GROUP BY
a.id,
a.name;

Related

How do you add two values from the same table and store in calculated record in the same table?

Hi I have one tables here:
equipment
ID, Owner, Type, Count
1 Bob phone 10
2 Larry computer 11
1 Bob computer 11
What I am trying to do is add the computers that Bob, with id 1, to the computers of Larry's, with id 2. I'm trying to increase the count. The count should be 11+11=22. The new computer count for id 2 should be 22 and should update like this in the database:
equipment
ID, Owner, Type, Count
1 Bob phone 10
2 Larry computer 22
1 Bob computer 11
If Bob did not have any computer, meaning there was no record with ID = 2, then the record should be created.
Here is my SQL:
INSERT INTO EQUIPMENT(`ID`, `OWNER`, `TYPE`, `COUNT`)
SELECT 1 as t.ID, t.OWNER, t.TYPE, t.COUNT
FROM EQUIPMENT t
WHERE t.ID = 2
on duplicate key
update
COUNT = COUNT + t.COUNT;
Why are you using insert to update a row?
update equipment e cross join
(select e1.* from equipment e1 where e1.id = 1) as e1
select e.count = e.count + e1.count
where e.id = 2;
Some thing like this
UPDATE Yourtable a
JOIN Yourtable b
ON a.NAME = b.NAME
AND a.ID = b.ID + 1
SET a.Count = a.Count + b.Count

MYSQL LEFTJOIN multiple ids same table

Im trying to get a combination of ids from a table like this:
Table activation:
user_id product_id reseller_id range_id Name
-------------------------------------------------
1 1 5 2 Oscar
1 1 5 3 Luis
2 1 5 4 Julian
Table prices (compType_id = reseller_id):
product_id compType_id price range_id
------------------------------------------------
1 5 38.60 2
1 5 48.60 3
1 5 58.60 4
Table users:
user_id name
----------------
1 lloyd
2 Mark
I want to select the activation Name and the price of prices based on the user_id.
How can i do that?
I tried something like this:
SELECT a.name
(SELECT price FROM prices WHERE product_id = 1 AND range_id =
AND compType_id = 5) AS price
FROM activation AS a
LEFT JOIN users AS u ON u.user_id = a.u_id
WHERE u.user_id = 1
The price columns have the same value in each row.
name price
Oscar 21.30
Luis 21.30
How can i change it to show the correct price?
I solved it with something like this:
SELECT a.company, a.name, a.email, a.phone, a.ruc, a.code, a.active,
a.numlic, (SELECT p.price FROM prices AS p WHERE p.product_id =
a.product_id AND p.range_id = a.range_id AND p.compType_id = c.type_id)
AS price
FROM activation AS a
LEFT JOIN users AS u ON u.user_id = a.u_id
LEFT JOIN companies AS c ON a.reseller_id = c.id
WHERE u.user_id = 1

MySQL - Display null column from child table if all values are not distinct

I have the following tables, for example:
invoices
ID Name
1 A
2 B
3 C
4 D
5 E
transactions
ID Invoice_ID User_ID
1 1 10
2 1 10
3 1 10
4 2 30
5 3 20
6 3 40
7 2 30
8 2 30
9 4 40
10 3 50
Now I want to make a select that will pull the invoices and the user_id from the related transactions, but of course if I do that I won't get all the ids, since they may be distinct but there will be only one column for that. What I want to do is that if there are distinct User_ids, I will display a pre-defined text in the column instead of the actual result.
select invoices.id, invoices.name, transactions.user_id(if there are distinct user_ids -> return null)
from invoices
left join transactions on invoices.id = transactions.invoice_id
and then this would be the result
ID Name User_ID
1 A 10
2 B 30
3 C null
4 D 40
5 E null
Is this possible?
You can do the following :
select
invoices.id,
invoices.name,
IF (
(SELECT COUNT(DISTINCT user_id) FROM transactions WHERE transactions.invoice_id = invoices.id) = 1,
(SELECT MAX(user_id) FROM transactions WHERE transactions.invoice_id = invoices.id),
null
) AS user_id
from invoices
Or, alternatively, you can use the GROUP_CONCAT function to output a comma-separated list of users for each invoice. It is not exactly what you asked, but maybe in fact it will be more useful :
select
invoices.id,
invoices.name,
GROUP_CONCAT(DISTINCT transactions.user_id SEPARATOR ',') AS user_ids
from invoices
left join transactions on invoices.id = transactions.invoice_id
group by invoices.id
Try somethingh like:
select i.id, i.name, t.user_id
from invoices i left join
(
select invoice_ID, User_ID
from transactions
group by invoice_ID
having count(invoice_ID)=1
) t on i.id=t.invoice_id
SQL fiddle
You could list all the transactions that have multiple user ids, like this:
select invoices.id, invoices.name, null
from invoices
left join transactions on invoices.id = transactions.invoice_id having count(distinct transactions.user_id) > 1
Also, I think this CASE might suit your needs here:
select invoices.id, invoices.name,
case when count(distinct transactions.user_id) > 1 then null else transactions.user_id end
from invoices
left join transactions on invoices.id = transactions.invoice_id
group by invoices.id
although, I'm not sure this is syntactically correct

MySQL : Don't select duplicate row item when one of them has status = 1

have a table with duplicate data, I'm able to group email by using this query
SELECT id, first_name, email, status FROM customers WHERE status = '0' GROUP BY email
However, I don't want to select customer with duplicate emails that already have the status = '1'
Table design as follows...
id first_name email status
1 Tony tony#gmail.com 0
2 Terry terry#gmail.com 0
3 Alex alex#gmail.com 0
4 John john#gmail.com 0
5 Mike mike#gmail.com 1
6 Mike Jones mike#gmail.com 0
7 Mike Fake mike#gmail.com 0
my query still selects mike#gmail.com because there are status with 0 but in fact, there's one already with the status=1.... How do I not select the email that already have the status=1 ?
Try this:
Using LEFT JOIN
SELECT c.id, c.first_name, c.email, c.status
FROM customers c
LEFT OUTER JOIN customers c1 ON c.email = c1.email AND c1.cstatus = 1
WHERE c.status = 0 AND c1.id IS NULL
GROUP BY c.email;
Using NOT EXISTS
SELECT c.id, c.first_name, c.email, c.status
FROM customers c
WHERE c.status = 0 AND
NOT EXISTS (SELECT 1 FROM customers c1 WHERE c.email = c1.email AND c1.cstatus = 1)
GROUP BY c.email;
The simplest way to do it would be using not exists
select c.* from customers c where not exists
(
select 1 from customers c1
where c1.email = c.email
and c1.status = 1
)
SELECT id, first_name, email, status,
COUNT(CASE WHEN status = '0' THEN 1 END) AS zero_status_count
COUNT(CASE WHEN status = '1' THEN 1 END) AS one_status_count
FROM customers GROUP BY email having zero_status_count > 0 and one_status_count < 1;
try this.

mySQL - GROUP BY but get the most recent row

I've got a budget table:
user_id product_id budget created
-----------------------------------------------------------------
1 1 300 2011-12-01
2 1 400 2011-12-01
1 1 500 2011-12-03
2 2 400 2011-12-04
I've also got a manager_user table, joining a manager with the user
user_id manager_id product_id
------------------------------------
1 5 1
1 9 2
2 5 1
2 5 2
3 5 1
What I'd like to do is grab each of the user that's assigned to Manager #5, and also get their 'budgets'... but only the most recent one.
Right now my statement looks like this:
SELECT * FROM manager_user mu
LEFT JOIN budget b
ON b.user_id = mu.user_id AND b.product_id = mu.product_id
WHERE mu.manager_id = 5
GROUP BY mu.user_id, mu.product_id
ORDER BY b.created DESC;
The problem is it doesn't pull the most recent budget. Any suggestions? Thanks!
To accomplish your task you can do as follows:
select b1.user_id,
b1.budget
from budget b1 inner join (
select b.user_id,
b.product_id,
max(created) lastdate
from budget b
group by b.user_id, b.product_id ) q
on b1.user_id=q.user_id and
b1.product_id=q.product_id and
b1.created=q.lastdate
where b1.user_id in
(select user_id from manager_user where manager_id = 5);
I'm assuming here that your (user_id, product_id, created) combination is unique.
For what it's worth, here's the code that returned what I was looking for:
SELECT DISTINCT(b1.id),mu.user_id,mu.product_id,b1.budget,b1.created
FROM budget b1
INNER JOIN (
SELECT b.user_id, b.product_id, MAX(created) lastdate
FROM budget b
GROUP BY b.user_id, b.product_id) q
ON b1.user_id=q.user_id AND
b1.product_id=q.product_id AND
b1.created=q.lastdate
RIGHT JOIN manager_user mu
ON mu.user_id = b1.user_id AND
mu.product_id = b1.product_id
WHERE mu.manager_id = 5;
Thanks for the help Andrea!