How to express nested SELECTS as a simpler JOIN - sql

I have three tables:
customers: id, name
transactions: id_customer, id_item
items: id, name
I want to write a simple query that will return the names of all customers who ordered an item with the name 'apple'
I know I can do something like:
SELECT
name
FROM
customers
WHERE id IN (SELECT
id_customer
FROM
transactions
WHERE id_item IN (SELECT
id
FROM
items
WHERE name = 'apple'))
This may not be too bad, but it seems convoluted and like there might be a more straightforward way to do this with a join?

Yes, it's definitely better to use a join in this case. Try this:
SELECT DISTINCT
A.name
FROM
customers A INNER JOIN
transactions B ON A.id = B.id_customer INNER JOIN
items C ON B.id_item = C.id
WHERE C.name = 'apple'
In this way, only customers who placed an order containing 'apple's will be shown.

Use Join case, this a best way to approach.
Select C.name from Customers C
Inner Join Transaction T on C.id = T.id_customer
Inner Join Items I on T.id_items = I.id
where I.name = "Apple"
Above query will return the names of all customers who ordered "Apple".

Related

Modify SQL query to include cases without a value

I have this database assignment where I need to write a query "to display the id and name of each category, with the number of products that belong to the category". I was able to solve it and used this query.
SELECT Category.Id, Category.Name, COUNT(Category.Name)
FROM Category, Product
WHERE (CategoryId = Category.Id)
GROUP BY Category.Id;
But I want to modify it to make all categories appear, even those with no products. Stuck on this part. Any help is appreciated.
You can left join:
select c.id, c.name, count(p.categoryid) cnt_products
from category c
left join product p on p.categoryid = c.id
group by c.id;
A correlated subquery is also a fine solution, which avoids outer aggregation:
select c.*,
(select count(*) from product p where p.categoryid = c.id) cnt_products
from category c

How to make this query on PostgreSQL?

I have three tables:
Customer table
Product Table
Customer_Product Table
I need to make query: Search for customers who bought a certain product (for example, name = "toilet paper") at least 2 times
I don't understand how.. I'm noob in databases.. Please help
You need aggregation :
select c.name
from customer c inner join
customer_product cp
on cp.customer_id = c.customer_id inner join
product p
on p.product_id = cp.product_id
where p.lable = 'toilet paper'
group by c.name
having count(p.lable) > 1;

Best way of excluding customers with a specific order

I'm running a pretty basic query. The issue is I'm trying to get results with all of our customers who never ordered product Y. The problem is, if I use a simple WHERE ProductColumn <> 'Product Y', it doesn't work because almost all of our customers have ordered other products.
Basically, I'm wondering how I could exclude on the customer level (instead of the order level) - if a customer has ordered Product Y, I don't want them showing up in my results at all.
Thanks.
You are probably looking for EXISTS().
If I want to find customers who have placed orders:
SELECT c.*
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customerid = c.customerID
AND productID = 'Y'
)
If I want to find customers who have not placed orders:
SELECT c.*
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.customerid = c.customerID
AND productID = 'Y'
)
Try this:
select * from customers c
where not exists(select 1 from customers
where cutomer_id = c.customer_id
and productcolumn = 'product y')
This assumes you have 'customer_id' column (or at least some id column in your table).
Simple LEFT JOIN should work:
SELECT c.*
FROM customers c
LEFT OUTER JOIN orders o
ON o.customerid = c.customerID
WHERE o.ProductColumn <> 'Product Y'

Combine Two Tables in Select (SQL Server 2008)

If I have two tables, like this for example:
Table 1 (products)
id
name
price
agentid
Table 2 (agent)
userid
name
email
How do I get a result set from products that include the agents name and email, meaning that products.agentid = agent.userid?
How do I join for example SELECT WHERE price < 100?
Edited to support price filter
You can use the INNER JOIN clause to join those tables. It is done this way:
select p.id, p.name as ProductName, a.userid, a.name as AgentName
from products p
inner join agents a on a.userid = p.agentid
where p.price < 100
Another way to do this is by a WHERE clause:
select p.id, p.name as ProductName, a.userid, a.name as AgentName
from products p, agents a
where a.userid = p.agentid and p.price < 100
Note in the second case you are making a natural product of all rows from both tables and then filtering the result. In the first case you are directly filtering the result while joining in the same step. The DBMS will understand your intentions (regardless of the way you choose to solve this) and handle it in the fastest way.
This is a very rudimentary INNER JOIN:
SELECT
products.name AS productname,
price,
agent.name AS agentname
email
FROM
products
INNER JOIN agent ON products.agentid = agent.userid
I recommend reviewing basic JOIN syntax and concepts. Here's a link to Microsoft's documentation, though what you have above is pretty universal as standard SQL.
Note that the INNER JOIN here assumes every product has an associated agentid that isn't NULL. If there are NULL agentid in products, use LEFT OUTER JOIN instead to return even the products with no agent.
select p.name productname, p.price, a.name as agent_name, a.email
from products p
inner join agent a on (a.userid = p.agentid)
This is my join for slightly larger tables in Prod.Hope it helps.
SELECT TOP 1000 p.[id]
,p.[attributeId]
,p.[name] as PropertyName
,p.[description]
,p.[active],
a.[appId],
a.[activityId],
a.[Name] as AttributeName
FROM [XYZ.Gamification.V2B13.Full].[dbo].[ADM_attributeProperty] p
Inner join [XYZ.Gamification.V2B13.Full].[dbo].[ADM_activityAttribute] a
on a.id=p.attributeId
where a.appId=23098;
select ProductName=p.[name]
, ProductPrice=p.price
, AgentName=a.[name]
, AgentEmail=a.email
from products p
inner join agent a on a.userid=p.agentid
If you don't want to use inner join (or don't have possibility to do it!) and would combine rows, you can use a cross join :
SELECT *
FROM table1
CROSS JOIN table2
or simply
SELECT *
FROM table1, table2

How to do a join with multiple conditions in the second joined table?

I have 2 tables. The first table is a list of customers.
The second table is a list of equipment that those customers own with another field with some data on that customer (customer issue). The problem is that for each customer, there may be multiple issues.
I need to do a join on these tables but only return results of customers having two of these issues.
The trouble is, if I do a join with OR, I get results including customers with only one of these issues.
If I do AND, I don't get any results because each row only includes one condition.
How can I do this in T-SQL 2008?
Unless I've misunderstood, I think you want something like this (if you're only interested in customers that have 2 specific issues):
SELECT c.*
FROM Customer c
INNER JOIN CustomerEquipment e1 ON c.CustomerId = e1.CustomerId AND e1.Issue = 'Issue 1'
INNER JOIN CustomerEquipment e2 ON c.CustomerId = e2.CustomerId AND e2.Issue = 'Issue 2'
Or, to find any customers that have multiple issues regardless of type:
;WITH Issues AS
(
SELECT CustomerId, COUNT(*)
FROM CustomerEquipment
GROUP BY CustomerId
HAVING COUNT(*) > 1
)
SELECT c.*
FROM Customer c
JOIN Issues i ON c.CustomerId = i.CustomerId
SELECT *
FROM customers as c
LEFT JOIN equipment as e
ON c.customer_id = e.customer_id --> what you are joining on
WHERE (
SELECT COUNT(*)
FROM equipment as e2
WHERE e2.customer.id = c.customer_id
) > 1
You can do it with a sub query instead of Joins:
select * from Customer C where (select Count(*) from Issue I where I.CustomerID = C.CustomerID) < 2
or whatever value you want