I have following query which gives correct result but I want to use not exist instead of not in.
select cust_name from customer
where cust_id not in
(select cust_id from ord where ord_id in
(select ord_id from orderitem where prod_id in
(select prod_id from product
WHERE PROD_DESCRIP = 'Guide to Tennis')))
Furthermore I have tried -
select cust_name from customer
where cust_id not exists
(select cust_id from ord where ord_id in
(select ord_id from orderitem where prod_id in
(select prod_id from product
WHERE PROD_DESCRIP = 'Guide to Tennis')))
I am not sure whether it is true or not
You don't put the column name before NOT EXISTS, it's just WHERE NOT EXISTS (subquery).
You then need to make it a correlated subquery, comparing the cust_id in the outer table with the cust_id in the inner table.
select cust_name
from customer AS c
where not exists
(select 1
from ord AS o
where ord_id in
(select ord_id from orderitem where prod_id in
(select prod_id from product WHERE PROD_DESCRIP = 'Guide to Tennis'))
and o.cust_id = c.cust_id)
In general, it's better to use JOIN than WHERE xxx IN -- MySQL tends to optimize it better.
select cust_name
from customer AS c
where not exists
(select 1
from ord AS o
join orderitem AS oi ON o.ord_id = oi.ord_id
join product AS p ON oi.prod_id = p.prod_id
where p.prod_descrip = 'Guide to Tennis'
and o.cust_id = c.cust_id)
And you can do the NOT EXISTS using a LEFT JOIN pattern.
select cust_name
from customer AS c
left join ord AS o ON o.cust_id = c.cust_id
left join orderitem AS oi ON o.ord_id = oi.ord_id
left join product AS p ON oi.prod_id = p.prod_id AND p.prod_descrip = 'Guide to Tennis'
where o.cust_id IS NULL
Related
In MySQL I have 4 tables:
- product(id)
- order(id)
- order_detail_1(id, product_id, order_id, qty)
- order_detail_2(id, product_id, order_id, qty)
I want to get the sum of the quantity of products sold from the 2 tables (order_detail_1, order_detail_2) grouping them by product
produt can existe in order_detail_1 and not in order_detail_2 and vice versa
i tested this query and it worked but I want a simpler query without the union and the subquery.
select tmp.product_id ,sum(tmp.qty) from
(
(
select order_detail_1.product_id ,sum(order_detail_1.qty)
from order_detail_1
inner join order on order_detail_1.id_order = order.id
where order_detail_1.product_id is not null
group by order_detail_1.product_id
)
union all
(
select order_detail_2.product_id ,sum(order_detail_2.qty)
from order_detail_2
inner join order on order_detail_2.id_order = order.id
where order_detail_2.product_id is not null
group by order_detail_2.product_id
)
) tmp
group by tmp.product_id
It looks like you're not using order table other then checking if it exists, so you can use EXISTS()
SELECT p.product_id,sum(p.qty) as qty
FROM (SELECT product_id,qty,id_order FROM order_detail_1
WHERE product_id IS NOT NULL
UNION ALL
SELECT product_id,qty,id_order FROM order_detail_2
WHERE product_id IS NOT NULL) p
WHERE EXISTS(SELECT 1 FROM order o
WHERE o.id = p.id_order)
GROUP BY p.product_id
If a product is in only one table, you can use left join:
select p.id, (coalesce(sum(od1.qty), 0) + coalesce(sum(od2.qty, 0))) as qty
from product p left join
order_detail_1 od1
on od1.product_id = p.id left join
order_detail_2 od2
on od2.product_id = p.id
group by p.id;
This formulation depends on the fact that the two tables are exclusion -- a product is in only one table.
EDIT:
If products can exist in both tables, then you need to aggregate them first:
select p.id, (coalesce(od1.qty, 0) + coalesce(od2.qty, 0)) as qty
from product p left join
(select product_id, sum(qty) as qty
from order_detail_1 od1
group by product_id
) od1
on od1.product_id = p.id left join
(select product_id, sum(qty) as qty
from order_detail_2 od2
group by product_id
) od2
on od2.product_id = p.id;
I am trying to show the average price of products bought by customers from ‘Tucson’, however this query returns null even though there are two customers that have placed orders from Tuscon.
select AVG(product_price) from product where product_id in
(select product_id from orderline where order_id in
(select order_id from ordertable where cust_id in
(Select cust_id from customer where city = 'Tuscon')))
You're using fom instead of from in your query: select order_id fom ordertable where cust_id in
This should be select order_id from ordertable where cust_id in
fom is not a recognized keyword. The MySQL parser doesn't know what to do with that, so it throws an error about "invalid syntax".
Consider using join operations in place of nested IN subqueries. If we are guaranteed:
product_id is unique in product table
order_id is unique in ordertable table
cust_id is unique in customer table
then we can get an equivalent result set, the average of the price of distinct products that were ordered...
SELECT AVG(p.product_price)
FROM ( SELECT l.product_id
FROM orderline l
JOIN ordertable o
ON o.order_id = l.order_id
JOIN customer c
ON c.cust_id = o.cust_id
WHERE c.city = 'Tuscon'
GROUP BY l.product_id
) q
JOIN product p
ON p.product_id = l.product_id
If we want that "average price" of all products ordered (a different result, with the average taking into account the number of times a product was ordered...then we could use a query like this:
SELECT AVG(p.product_price)
FROM product p
JOIN orderline l
ON l.product_id = p.product_id
JOIN ordertable o
ON o.order_id = l.order_id
JOIN customer c
ON c.cust_id = o.cust_id
WHERE c.city = 'Tuscon'
I need to find the first and last name of the customer who has purchased the most expensive product.
Schema
Orders
orderID
ordertypeID
customerID
quantity
purchasedate
Customers
customerID
state
postcode
streetNumber
streetAddress
customerLn
customerFn
Order_Contents
orderID
productID
quantity
Products
productID
productCategory
productName
productDescription
unitPrice
inStock
How can i write this query?
You can use sub queries as follows.
select
Customers.customerFN,
Customers.customerLN
from
Customers
inner join Orders on Orders.customerID = Customers.customerID
inner join Order_Contents on Order_Contents.orderID = Orders.orderID
where
Order_Contents.productID in
(select Products.productID from Products where Products.unitPrice = (select max(Products.unitPrice) from Products))
Something like this seems like it should work as a jumping off point (completely naive approach here)
SELECT CustomerFn, CustomerLn FROM Customers c
LEFT JOIN Orders o on o.customerID = c.customerID
LEFT JOIN Order_Contents oc on oc.orderID = o.orderID
LEFT JOIN Products p on p.productID = oc.productID
WHERE oc.productID IN (
SELECT productID FROM Products WHERE unitPrice = MAX(unitPrice)
);
select c.customerFn, c.customerLn
from customers c join orders o where o.customerID = c.customerID
join order_contents l where l.orderId = o.orderId
join products p where p.productId = l.productId
order by p.unitPrice desc
limit 1
I'm using MySQL database server. My query is:
Count how many customers that they just have 1 order and how many customers that they have more than 1 orders.
This is my SQL query:
SELECT
COUNT((SELECT
customer_code
FROM
customer AS c
LEFT JOIN
order_info AS oi ON (c.customer_code = oi.customer_code)
GROUP BY customer_code
HAVING COUNT(id_order) = 1)) AS New_customers
How can I get this result.
You are grouping by customer_code before counting, I think this will group the rows together thus effectively removing all orders from the resultset. HAVING will always use the result set as the 'data feed'.
SELECT
COUNT(DISTINCT customer_code)
FROM
customer AS c
LEFT JOIN order_info AS oi ON (c.customer_code = oi.customer_code)
HAVING COUNT(id_order) = 1
OR a lot simpler (but perhaps not more efficient)
SELECT
COUNT(customer_code)
FROM
customer AS c
WHERE (
SELECT
COUNT(*)
FROM `order_info`
WHERE
`customer_code` = `c`.`customer_code`
) = 1
To get the number of customers with more than one order, simply change the = into > where appropiate.
SELECT
count(customer_code)
FROM
customer AS c
LEFT JOIN
order_info AS oi ON (c.customer_code = oi.customer_code)
GROUP BY customer_code
HAVING COUNT(id_order) = 1
For customers having 1 order
SELECT count(customer_code) FROM customer AS c
INNER JOIN order_info AS oi ON (c.customer_code = oi.customer_code)
GROUP BY customer_code HAVING COUNT(id_order) = 1))
For customers having MORE THAn 1 order
SELECT count(customer_code) FROM customer AS c
INNER JOIN order_info AS oi ON (c.customer_code = oi.customer_code)
GROUP BY customer_code HAVING COUNT(id_order) > 1))
Try this
SELECT
count(*)
FROM
customer AS c
LEFT JOIN
order_info AS oi ON c.customer_code = oi.customer_code
HAVING COUNT(id_order) = 1
try this:
SELECT * FROM ( select c.customer_code, count(*) total FROM customer c
LEFT JOIN
order_info AS oi ON (c.customer_code = oi.customer_code)
GROUP BY customer_code) test
CASE total
WHEN 1 THEN SELECT total one_order FROM test;
ELSE
SELECT total more_order FROM test
In the following query I am trying to fetch data from tables: company, classes_by_company, and person. I have a foreign key in all tables with the name company_id. In the classes_by_company table a class can have a class_status that can be either active or inactive. The same goes for table person with its corresponding person_status. I am able to count the total number of classes and the total number of persons, find the working query here: SQFIDDLE. In the query below I am trying to incorporate the previous query but now also count the total number of class_status=ACTIVE and person_status=ACTIVE. I am getting error Not unique table/alias: 'c'. How can I can count the total number and the total number of active classes and person? SQLFIDDLE
SELECT a.id, a.company_id, a.status, c.class_status, p.person_status,
c.total_count AS classes_per_company,
p.total_count AS employees_per_company,
c.active_count AS active_classes,
p.active_count AS active_instructors
FROM company a
LEFT JOIN (SELECT company_id, COUNT(*) as total_count
FROM classes_by_company
GROUP BY company_id) c
ON a.company_id = c.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as active_count
FROM classes_by_company
WHERE class_status = 'ACTIVE'
GROUP BY company_id) c
ON a.company_id = c.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as total_count
FROM person
GROUP BY company_id) p
ON a.company_id = p.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as active_count
FROM person
WHERE person_status = 'ACTIVE'
GROUP BY company_id) p
ON a.company_id = c.company_id
Table Structure:
CREATE TABLE company
(
id int auto_increment primary key,
company_id int,
status varchar(20)
);
CREATE TABLE classes_by_company
(
id int auto_increment primary key,
company_id int,
class_name varchar(20),
class_status varchar(20)
);
CREATE TABLE person
(
id int auto_increment primary key,
employee_id int,
company_id int,
person_name varchar(20),
person_status varchar(20)
);
Your query structure is fine, you just need to give different aliases to each subquery that you join with.
You also failed to return class_status and person_status from the c and p subqueries.
SELECT a.id, a.company_id, a.status, c.class_status, p.person_status,
c.total_count AS classes_per_company,
p.total_count AS employees_per_company,
ca.active_count AS active_classes,
pa.active_count AS active_instructors
FROM company a
LEFT JOIN (SELECT company_id, class_status, COUNT(*) as total_count
FROM classes_by_company
GROUP BY company_id) c
ON a.company_id = c.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as active_count
FROM classes_by_company
WHERE class_status = 'ACTIVE'
GROUP BY company_id) ca
ON a.company_id = ca.company_id
LEFT JOIN (SELECT company_id, person_status, COUNT(*) as total_count
FROM person
GROUP BY company_id) p
ON a.company_id = p.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as active_count
FROM person
WHERE person_status = 'ACTIVE'
GROUP BY company_id) pa
ON a.company_id = pa.company_id
I changed the aliases to ca for active classes, and pa for active person.
SQLFIDDLE
You can also reduce the number of joins by counting the active rows in the same query as the total rows:
SELECT a.id, a.company_id, a.status, c.class_status, p.person_status,
c.total_count AS classes_per_company,
p.total_count AS employees_per_company,
c.active_count AS active_classes,
p.active_count AS active_instructors
FROM company a
LEFT JOIN (SELECT company_id, class_status, COUNT(*) as total_count, SUM(class_status = 'ACTIVE') as active_count
FROM classes_by_company
GROUP BY company_id) c
ON a.company_id = c.company_id
LEFT JOIN (SELECT company_id, person_status, COUNT(*) as total_count, SUM(person_status = 'ACTIVE') as active_count
FROM person
GROUP BY company_id) p
ON a.company_id = p.company_id
SQLFIDDLE
Very small change...table alias's (or subqueries) cannot be the same
SELECT a.id, a.company_id, a.status, c.class_status, p.person_status,
c.total_count AS classes_per_company,
p.total_count AS employees_per_company,
ca.active_count AS active_classes,
pa.active_count AS active_instructors
FROM company a
LEFT JOIN (SELECT company_id, COUNT(*) as total_count
FROM classes_by_company
GROUP BY company_id) c
ON a.company_id = c.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as active_count
FROM classes_by_company
WHERE class_status = 'ACTIVE'
GROUP BY company_id) ca
ON a.company_id = c.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as total_count
FROM person
GROUP BY company_id) p
ON a.company_id = p.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as active_count
FROM person
WHERE person_status = 'ACTIVE'
GROUP BY company_id) pa
ON a.company_id = c.company_id