I have a query that I feel is very bulky and can do with optimisation. First thing would obviously be replacing not in subquery with join but it affects the sub-sub query that I have. I'd appreciate suggestions/workaround on it.
This is the query
SELECT *
FROM lastweeksales
WHERE productID = 1234
AND retailer NOT
IN (
SELECT retailer
FROM sales
WHERE productID
IN (
SELECT productID
FROM products
WHERE publisher = 123
)
AND DATE = date(now())
)
Basically, I want to get rows from lastweek's sales on a product where retailers are not present that did sales today but sales should only be on products by a certain publisher.
:S:S:S
You can group together 2 inner subqueries easily via INNER JOIN. For the outer one you should use LEFT OUTER join and then filter on retailer IS NULL, like this:
SELECT lws.*
FROM lastweeksales lws
LEFT JOIN (SELECT s.retailer
FROM sales s
JOIN products p USING (productID)
WHERE p.publisher = 123
AND s.date = date(now())) AS r
ON lws.retailer = r.retailer
WHERE r.retailer IS NULL;
Related
I have the following tables in my database.I only listed the important columns which can be used for joining.
I need to get the following output
Currently I'm using two seperate queries for each COUNT value
For assigned licenses
select
products.id,products.name,COUNT(assigned_licenses.id)
from
deployment_users
inner join
assigned_licenses
on
deployment_users.id = assigned_licenses.deployment_user_id
inner join
products
on
assigned_licenses.id = products.id
and
deployment_users.customer_id = 10
group by
assigned_licenses.id
;
For total licenses
select
products.id,products.name,COUNT(total_licenses.id)
from
customers
inner join
total_licenses
on
customers.iccode = licenses.iccode
inner join
products
on
total_licenses.id = products.id
and
customers.id = 10
group by
total_licenses.id
;
Since there are more than a 1,000 products that need to be listed,I want to combine them into a single query.How can I do that?
Your specification leaves some room for interpretation (e.g. can a user have assigned licenses without total licenses? if yes my query will fail.) but I would go with this.
SELECT
products.id,
products.name,
Count(Distinct total_licenses.id) As CountTotalLicenses,
Count(Distinct assigned_liceses.deployment_users_id) As CountAssignedLicenses
FROM products
LEFT JOIN total_licenses ON total_licenses.products_id = products.id
LEFT JOIN customers ON customers.iccode = total_licenses.customers_iccode
LEFT JOIN assigned_licenses ON assigned_liceses.total_licenses_id = total_licenses.id
WHERE
customers.id = 10
GROUP BY
products.id,
products.name
For the future it would be awesome if you could paste code as code and not as an image. People cannot simple copy paste snippets of your code and have to type everything again...
Try joining Both of your query
SELECT * FROM (
(First Query) as assigned_licn
INNER JOIN
(Second Query) as total_licn
USING (id)
);
I have a product-table and a table containing all parts of a product and the quantity.
Structure of products table:
id
name
Structure of parts table:
id
productsId
partsId
quantity
Now I want to get all products and for every product the total quantity parts and quantity of different parts . The current solution is this query:
SELECT
products.*,
(
SELECT count(quantity)
FROM product_has_part
WHERE product_has_part.productsId = products.id
) AS partsQty,
(
SELECT sum(quantity)
FROM product_has_part
WHERE product_has_part.productsId = products.id
) AS sumQty
FROM products
Now I have to subselects across the same table. So I think there must be a better way to create this query?
use join
Select *,count(quantity),sum(quantity)
From products p join
product_has_part pp on pp.productsId = p.id
FROM products
or Group by use for count or sum for each id
Select *,count(quantity),sum(quantity)
From products p join
product_has_part pp on pp.productsId = p.id
FROM products
Group by p.id
p.f1, p.f2, p.f3 mean each field of p.
select p.f1, p.f2, p.f3 ... count(php.quantity), sum(php.quantity)
from products p
join product_has_part php
on p.productsId = php.productsId
group by p.f1, p.f2, p.f3 ..
I have been going round in circles now for a couple of days with this query and it's driving me nuts. I've found partial answers using max(date) and left joins but have as yet failed to achieve the right result so would be very grateful for any help.
I have 3 tables:-
inventory
id
lots of other fields...
sale_price
id
date
*ticket_type_id
*inventory_id
ticket_type
id
ticket_name
The sale_price table is updated with a date and new ticket type every time the sale price is changed. All I want to do is display:-
find the latest record in sale_price
display the inventory information related to this
display the ticket_name relating to this
The query that I have arrived at is:-
$result = "
SELECT DISTINCT inv.*, tt.ticket_name, MAX(sp.date) AS spdate
FROM sale_price sp
LEFT
JOIN ticket_type tt
ON sp.ticket_type_id = tt.id
JOIN inventory inv
ON sp.inventory_id = inv.id
GROUP
BY sp.inventory_id
";
but it's clearly not working. I would be really grateful for any help you can give and (if it's not too much to as) a bit of detail on where I'm going wrong.
many thanks in anticipation!
If you only want to know the latest record of all then you could use following query:
SELECT
s.ticket_type_id,
s.inventory_id,
t.ticket_name,
i.lots of other fields
FROM
sale_price s
INNER JOIN
inventory i
ON
s.inventory_id = i.id
INNER JOIN
ticket_type t
ON
s.ticket_type_id = t.id;
WHERE
s.date = (
SELECT
MAX(s1.date)
FROM
sale_price s1
)
If you need the latest record for every inventory item, then you've got to extend this query by using the equality of the inventory_id in the WHERE clause of the subselect:
SELECT
s.ticket_type_id,
s.inventory_id,
t.ticket_name,
i.lots of other fields
FROM
sale_price s
INNER JOIN
inventory i
ON
s.inventory_id = i.id
INNER JOIN
ticket_type t
ON
s.ticket_type_id = t.id;
WHERE
-- gives us the newest date per inventory_id
s.date = (
SELECT
MAX(s1.date)
FROM
sale_price s1
WHERE
s.inventory_id = s1.inventory_id
)
By the way, this is a correlated subquery and it could get slow.
I have a query to show customers and the total dollar value of all their orders. The query takes about 100 seconds to execute.
I'm querying on an ExpressionEngine CMS database. ExpressionEngine uses one table exp_channel_data, for all content. Therefore, I have to join on that table for both customer and order data. I have about 14,000 customers, 30,000 orders and 160,000 total records in that table.
Can I change this query to speed it up?
SELECT link.author_id AS customer_id,
customers.field_id_122 AS company,
Sum(orders.field_id_22) AS total_orders
FROM exp_channel_data customers
JOIN exp_channel_titles link
ON link.author_id = customers.field_id_117
AND customers.channel_id = 7
JOIN exp_channel_data orders
ON orders.entry_id = link.entry_id
AND orders.channel_id = 3
GROUP BY customer_id
Thanks, and please let me know if I should include other information.
UPDATE SOLUTION
My apologies. I noticed that entry_id for the exp_channel_data table customers corresponds to author_id for the exp_channel_titles table. So I don't have to use field_id_117 in the join. field_id_117 duplicates entry_id, but in a TEXT field. JOINING on that text field slowed things down. The query is now 3 seconds
However, the inner join solution posted by #DRapp is 1.5 seconds. Here is his sql with a minor edit:
SELECT
PQ.author_id CustomerID,
c.field_id_122 CompanyName,
PQ.totalOrders
FROM
( SELECT
t.author_id
SUM( o.field_id_22 ) as totalOrders
FROM
exp_channel_data o
JOIN
exp_channel_titles t ON t.author_id = o.entry_id AND o.channel_id = 3
GROUP BY
t.author_id ) PQ
JOIN
exp_channel_data c ON PQ.author_id = c.entry_id AND c.channel_id = 7
ORDER BY CustomerID
If this is the same table, then the same columns across the board for all alias instances.
I would ensure an index on (channel_id, entry_id, field_id_117 ) if possible. Another index on (author_id) for the prequery of order totals
Then, start first with what will become an inner query doing nothing but a per customer sum of order amounts.. Since the join is the "author_id" as the customer ID, just query/sum that first. Not completely understanding the (what I would consider) poor design of the structure, knowing what the "Channel_ID" really indicates, you don't want to duplicate summation values because of these other things in the mix.
select
o.author_id,
sum( o.field_id_22 ) as totalOrders
FROM
exp_channel_data customers o
where
o.channel_id = 3
group by
o.author_id
If that is correct on the per customer (via author_id column), then that can be wrapped as follows
select
PQ.author_id CustomerID,
c.field_id_122 CompanyName,
PQ.totalOrders
from
( select
o.author_id,
sum( o.field_id_22 ) as totalOrders
FROM
exp_channel_data customers o
where
o.channel_id = 3
group by
o.author_id ) PQ
JOIN exp_channel_data c
on PQ.author_id = c.field_id_117
AND c.channel_id = 7
Can you post the results of an EXPLAIN query?
I'm guessing that your tables are not indexed well for this operation. All of the columns that you join on should probably be indexed. As a first guess I'd look at indexing exp_channel_data.field_id_117
Try something like this. Possibly you have error in joins. also check whether joins on columns are correct in your databases. Cross join may takes time to fetch large data, by mistake if your joins are not proper on columns.
select
link.author_id as customer_id,
customers.field_id_122 as company,
sum(orders.field_id_22) as total_or_orders
from exp_channel_data customers
join exp_channel_titles link on (link.author_id = customers.field_id_117 and
link.author_id = customer.channel_id = 7)
join exp_channel_data orders on (orders.entry_id = link.entry_id and orders.entry_id = orders.channel_id = 3)
group by customer_id
I have one table Customers with CustomerID and PhoneNumber, the second table is Orders that has CustomerId and OrderNumber and a third table OrderDetails that has OrderNumber, PriceOfOneUnit and UnitsOrdered. I need to find the PhoneNumber for the customer who placed the largest order (PriceOfOneUnit * UnitsOrdered). Doing a count(PriceOfOneUnit*UnitsOrdered) as A1 and then `Group By CustomerId Order By A1 DESC LIMIT 1 is evidently not working after joining the 3 tables. Can anyone help.
If we take you at your word, and what you want is the biggest single line-item rather than the largest order, you can find the largest line-item and then find the order to which it belongs and then the customer who placed that order. You can use a dummy aggregate function to pull back the order id from orderDetails.
EDIT:
OK, for someone just starting out, I think it can be clearer to think in terms of Venn diagrams and use what are called Inline Views and subqueries:
select customername, phone
from customer
inner join
(
select o.id, customerid from orders o
inner join
(
select od.orderid from orderdetail od
where (od.qty * od.itemprice) =
(
select max(od.qty * od.itemprice)
from orderdetail as od
)
) as biggestorder
on o.id = biggestorder.orderid
) as X
on customer.id = X.customerid
Each of the queries inside parentheses returns a set that can be joined/intersected with other sets.
Give this a try,
SELECT cus.CustomerId, cus.PhoneNumber
FROM Customers cus
INNER JOIN Orders a
ON cus.CustomerId = a.CustomerId
INNER JOIN OrderDetails b
On a.OrderNumber = b.OrderNumber
GROUP BY cus.CustomerId, cus.PhoneNumber
HAVING SUM(b.PriceOfOneUnit * b.UnitsOrdered) =
(
SELECT SUM(b.PriceOfOneUnit * b.UnitsOrdered) totalOrdersAmount
FROM Orders aa
INNER JOIN OrderDetails bb
On aa.OrderNumber = bb.OrderNumber
GROUP BY aa.CustomerId
ORDER BY totalOrdersAmount DESC
LIMIT 1
)