Sub query in join with 3rd table - mysql

My Current Join Query
select c.email
, c.name
, o.created
, o.customerId
, o.code as order_code
, o.totalValue
,'cash' as description
, o.WalletCash as amount
from Order o join Customer c on o.customerId = c.id
where o.WalletCash > 0
and o.created BETWEEN '2022-03-16' AND '2022-03-16'
I want to make join or sub query with below query
select customerId from CustomerWallet where customerId =100
The Customer, CustomerWalletand Order tables are all associated by CustomerID.
How join 3rd table in join query in mysql?

You can alias the first query and use that with the second table.
select * from (select c.email
, c.name
, o.created
, o.customerId
, o.code as order_code
, o.totalValue
,'cash' as description
, o.WalletCash as amount
from Order o join Customer c on o.customerId = c.id
where o.WalletCash > 0
and o.created BETWEEN '2022-03-16' AND '2022-03-16') tab t join CustomerWallet c on t.order_code = c.order_code and c.order_code = like "%abc%"
or you can join all three tables together.
select c.email
, c.name
, o.created
, o.customerId
, o.code as order_code
, o.totalValue
,'cash' as description
, o.WalletCash as amount
from Order o join Customer c on o.customerId = c.id
join CustomerWallet w on w.order_code = order_code
where o.WalletCash > 0
and o.created BETWEEN '2022-03-16' AND '2022-03-16'
and w.order_code like "%abc%"

If you want to restrict the first query's result to customer IDs found in the second query, then use IN:
select c.email
, c.name
, o.created
, o.customerId
, o.code as order_code
, o.totalValue
,'cash' as description
, o.WalletCash as amount
from Order o join Customer c on o.customerId = c.id
where o.WalletCash > 0
and o.created BETWEEN '2022-03-16' AND '2022-03-16'
and c.id in
(
select customerId
from CustomerWallet
where order_code like '%abc%'
);
I see that there is an order_code in CustomerWallet. There is a code in your order table, too. Maybe you want to consider this in your lokup. Probably:
and (o.code, c.id) in
(
select cw.order_code, cw.customerId
from CustomerWallet cw
where cw.order_code like '%abc%'
);
IN and EXISTS are appropriate for such lookups. As opposed to a join they just ensure a match exists. With joins you could involuntarily produce duplicate rows in case the second itself returns the join criteria multifold.

Related

Retrieve customer who bought more than 13 different products who never purchased same product

I tried this. But I feel this gives people who ordered same product
SELECT DISTINCT Count(od.orderqty) OrderQty,
c.customerid,
od.productid
FROM sales.customer c
INNER JOIN sales.salesorderheader oh
ON c.customerid = oh.customerid
INNER JOIN sales.salesorderdetail od
ON oh.salesorderid = od.salesorderid
GROUP BY od.productid,
c.customerid
HAVING Count(od.productid) > 10
ORDER BY c.customerid
Not sure what flavor of SQL you're using but try this:
select t.CustomerID
from (
select c.CustomerID
, count(distinct od.ProductID) as DistinctCount
, count(od.ProductID) as Count
from Sales.Customer c
join Sales.SalesOrderHeader oh
on c.customerid = oh.customerid
join Sales.SalesOrderDetail od
on oh.SalesOrderID = od.SalesOrderID
group
by c.CustomerID
) as t
where t.DistinctCount = t.Count
and t.DistinctCount > 13
order
by t.CustomerID

mysql query taking long time to respond

SELECT t.id
, t.department
, t.owner
, t.client
, u.username as owner_name
, c.name as catagery
, d.dept_name as deptname
, t.periority
, t.status
, t.estimate
, cl.takeaway_name
from tbl_task t
JOIN tbl_user u
ON u.id = t.owner
JOIN tbl_task_catagery c
ON c.id = t.catagery
JOIN tbl_department d
ON d.id = t.department
JOIN tbl_clients cl
ON cl.id = t.client
and t.status = 0
and (t.id in (select task_id
from tbl_task_note tn
where tn.user_id = '69'
and tn.id in (select max(id)
from tbl_task_note tt
where tt.task_id = tn.task_id
)
)
)
order by t.id
Note : The above query is used for check users hold tasks. tbl_task_note table is used for check task notes for separate users task.
With this query you will get the task that have the last task_note registered, including the user, departament, client, and some other.
If it is what you need you can just do this.
select
t.id,
t.department,
t.owner,
t.client,
u.username as owner_name,
c.name as catagery,
d.dept_name as ptname,
t.periority,
t.status,
t.estimate,
cl.takeaway_name
from tbl_task t
INNER JOIN tbl_user u ON u.id=t.owner
INNER JOIN tbl_task_catagery c ON c.id=t.catagery
INNER JOIN tbl_department d ON d.id=t.department
INNER JOIN tbl_clients cl ON cl.id=t.client and t.status=0
INNER JOIN (select * from tbl_task_note where id =
(select max(id) from tbl_task_note)
)tb on tb.task_id = t.id
order by t.id
That way you can improve your query.
You shoud also ensure that your keys compared are foreign keys to get faster consults.

inner join three tables results in multiplied values

I'm trying to (let's say) gather a report on customers.
In that report I want to include sum of orders and ticket number for each client.
Tables:
Customer(id, name)
Order(id, customer_id, amount)
support_ticket(id, customer_id)
query:
select
c.id as 'Customer',
count(distinct t.id) as "Ticket count",
count(distinct o.id) as "Order count",
sum(o.amount) as 'Order Amount'
from customer as c
inner join `order` as o on c.id = o.customer_id
inner join support_ticket as t on c.id = t.customer_id
group by c.id
Since I join with customer.id on the two tables, I get all the rows "duplicated", since I get all possible combinations, so if the client as multiple tickets, the sum(o.amount) will we multiplied because of "duplicated rows"
sqlFiddle (mysql): http://sqlfiddle.com/#!9/ba39ba/13
sqlFiddle (pg): http://sqlfiddle.com/#!17/bc32e/7
It seems like a simple case but I've been looking at it too much I think, I can't find the proper way to do that report.
What am I doing wrong?
your best bet is to re-write the Aggregation off the Order table as as Derived Table;
EG
select
c.id as 'Customer',
count(distinct t.id) as "Ticket count",
o.amount as 'Order Amount' ,
o.[Order count]
from customer as c
inner join
(SELECT
o.customer_id,
sum(amount) as amount ,
count(distinct o.id) as "Order count"
from [order]
group by o.customer_id)
as o on c.id = o.customer_id
inner join support_ticket as t on c.id = t.customer_id
group by
c.id ,
o.amount ,
o.[Order count]
Note that the Derived Table Columns then are added to the group by clause at the bottom.
Cheers!
Just calculate order values in a sub-query and join it.
SELECT
c.id as 'Customer'
,count(DISTINCT st.id) as 'Ticket Count'
,o.`Order Count`
,o.amount as `Order Amount`
FROM customer c
INNER JOIN support_ticket st
on c.id = st.customer_id
INNER JOIN (
SELECT
customer_id
,SUM(amount) as 'amount'
,count(distinct id) as 'Order Count'
FROM `order`
group by customer_id
) o
on c.id = o.customer_id
GROUP BY c.id;
select c.id as 'Customer'
,t2.count_ticket as "Ticket count"
,t1.count_order as "Order count"
,t1.amount as 'Order Amount'
from customer as c
inner join (select customer_id
,count(id) as count_order
,sum(amount) as amount
from Order group by customer_id) t1
on c.id = t1.customer_id
inner join (select customer_id
,count(id) as count_ticket
from support_ticket group by customer_id) t2
on c.id = t2.customer_id
In cases like yours, when I think the solution of my problem should be fairly simple but I cant wrap my head around it, I tend to use a WITH clause.
Not because its better, but because it helps me to understand my code better by splitting up complexity. First I create a relatively simple temp. Solving the first part of my problem.
WITH temp AS (
SELECT
c.id AS "customer",
COUNT(DISTINCT o.id) AS "order_count",
SUM(o.amount) AS "order_amount"
FROM customer AS c
INNER JOIN "order" AS o on c.id = o.customer_id
GROUP BY c.id
)
Then I simply select the first half of my solution from temp, adding this way all intermediate results, and solve the second part of my initial sql.
SELECT
temp.customer,
COUNT(DISTINCT t.id) as "ticket_count",
temp.order_count,
temp.order_amount
FROM temp
INNER JOIN support_ticket as t on temp.customer = t.customer_id
GROUP BY temp.customer, temp.order_count, temp.order_amount
The principle is the same like in all previous answers, but SELECTS are separated and I can check them fast, and continue on if I'm happy with parts of the solution.

inner join 4 tables with group, order by, having clause

I have 4 table and i want to extract: id, nume, localitate, masina_id, nr_inmatriculare, an_fabricatie, rafinarie, marca, and sum (quantity+deliver_quantity) as total_quantity group by an_fabricatie , Order by marca, and put some having clouse.
I don’t know how to make this.
My query is as bellow , but I think isn't correct.
select c.id, c.nume,c.localitate,l.masina_id, i.nr_inmatriculare, i.an_fabricatie,
i.rafinarie, m.marca from clienti c inner join livrari l on c.id = l.id inner join incarcari I on l.incarcare_id = l.livrari_id inner join masina m on i.id_marca = m.id, sum(select quantity, deliver_quantity) as total_quantity group by an_fabricatie having quantity >1000 order by marca;
Incarcari table
Id|livrari_id|id_marca|nr_inmatriculare|an_fabricatie|rafinarie|aviz_incarcare|quantity|
Livrari table
Id|masina_id|client_id|incarcare_id|deliver_quantity|aviz_livrare
Masini table
Id|numar_inmatriculare|marca|an_fabricatie|
Clienti table
Id|nume|localitate|date_add|date_upd|
SELECT c.id, c.nume, c.localitate, l.masina_id, i.nr_inmatriculare, i.an_fabricatie, i.rafinarie, m.marca, (SUM(i.quantity) + SUM(l.deliver_quantity)) AS total_quantity
FROM clienti c
INNER JOIN livrari l ON c.id = l.id
INNER JOIN incarcari i ON l.incarcare_id = i.livrari_id
INNER JOIN masini m ON i.id_marca = m.id
GROUP BY i.an_fabricatie, c.id, c.nume,c.localitate,l.masina_id, i.nr_inmatriculare, i.rafinarie, m.marca
HAVING i.quantity > 1000
ORDER BY m.marca DESC;

Modify SQL query to get all users?

I currently have this query.
SELECT DISTINCT (o.customer_id), count( o.id ) AS orders, c.*
FROM `order` AS o LEFT JOIN customer AS c ON o.customer_id = c.id
GROUP BY customer_id
What it does is it returns all customers that have made an order and counts the number of orders each customer has made.
What I need to do is modify this query so it also returns those customers who haven't made an order. Do you have any idea how this would be done?
I tried to reverse the query but this didn't do the trick..
SELECT DISTINCT (o.customer_id), count( o.id ) AS orders, c.*
FROM customer AS c LEFT JOIN order AS o ON o.customer_id = c.id
GROUP BY o.customer_id
Try this.
SELECT o.customer_id, sum( case when o.id is not null then 1 else 0 end ) AS orders, c.*
FROM customer c
LEFT JOIN order o ON o.customer_id = c.id GROUP BY customer_id
What about:
SELECT DISTINCT (o.customer_id), count( o.id ) AS orders, c.*
FROM `order` AS o
LEFT OUTER JOIN customer AS c ON o.customer_id = c.id GROUP BY customer_id
SELECT o.customer_id, c.*
FROM customer AS c LEFT JOIN order AS o ON o.customer_id = c.id
WHERE o.id IS NULL
GROUP BY o.customer_id
You can also skip the "GROUP BY" clause because when the orders side is NULL, there is always only one row for the customer:
SELECT o.customer_id, c.*
FROM customer AS c LEFT JOIN order AS o ON o.customer_id = c.id
WHERE o.id IS NULL