Inner join on the same columns - sql

Customer Table
----------------------
CustomerName
Peter
Sam
Sales Table
-----------------------
ProductName Customer
Cloth Peter
Mobile Peter
Cloth Sam
Laptop Sam
Expected result
Customer
Sam
I want result as customer who buyed 'Cloths' but not 'Mobile', i tried
select c.CustomerName from Customer c inner join Sales s1 on (s1.customer = c.customername and s1.productname = 'Cloth') inner join Sales s2 on (s2.customer = c.customername and s2.productname != 'Mobile');
but it always return both entries
Customer
Peter
Sam
Sam

A correlated subquery would be better as you're not interested in getting multiple rows for customers who bought cloths multiple times.
select
c.CustomerName
from
Customer c
where
exists (
select null
from sales
where sales.customer = c.customername and
s1.productname = 'Cloth') and
not exists (
select null
from sales
where sales.customer = c.customername and
s1.productname = 'Mobile');

You can use the Oracle MINUS operator to make it simple;
SELECT "Customer" FROM SalesTable WHERE "ProductName"='Cloth'
MINUS
SELECT "Customer" FROM SalesTable WHERE "ProductName"='Mobile'
Another slightly more complex option is a LEFT JOIN;
SELECT DISTINCT s1."Customer"
FROM SalesTable s1
LEFT JOIN SalesTable s2
ON s1."Customer" = s2."Customer"
AND s2."ProductName" = 'Mobile'
WHERE s1."ProductName" = 'Cloth'
AND s2."Customer" IS NULL;
An SQLfiddle to test both with.

This is an example of a "set-within-sets" query. I think a good approach is to use aggregation:
select s.Customer
from Sales s
group by s.Customer
having sum(case when s.ProductName = 'Cloth' then 1 else 0 end) > 0 and -- has cloth
sum(case when s.ProductName = 'Mobile' then 1 else 0 end) = 0 -- does not have mobile
I prefer putting the logic in the having clause, because it is quite flexible. You can add additional conditions quite easily for other products.

try this:
select c.CustomerName
from Customer c
where exists(select 1 from sales s1 where s1.customer = c.customername and s1.productname = 'Cloth')
and not exists (select 1 from sales s2 where s2.customer = c.customername and s2.productname = 'Mobile')

first of all you should review your database schema.
You never do inner join without an id.
Try to create your tables using relationships. Like this:
create table customer
(
id_customer int not null,
ds_customername varchar(80) null,
primary key (id_customer)
)
create table products
(
id_product int not null,
ds_product varchar(100) null,
primary key (id_product)
)
create table sales
(
id_sales int not null,
id_product int not null,
id_customer int not null,
foreign key (id_product) references products (id_product),
foreign key (id_customer) references customer (id_customer)
)
select customer.ds_customername
from customer
inner join sales (customer.id_customer = sales.id_customer)
inner join products (products.id_product = sales.id_product)
where products.ds_product = 'Cloth'
Ok,
if you can't do this, you can do your query (in an old way) this:
select Customer.customername
from Customer
inner join on (customer.customername = sales.customer)
where sales.productname = 'Cloth'
I hope help you.
Hugs,
Vin.

Related

qrying DB where two customers in one order

lets say I have two tables,
Order
order_id (PK)
ordered_date
CustomerOrders
Customer_order_id (PK)
order_id (FK)
customer_type(char1) ( can be S, T and M)
If one or more different types of customers involved in an order, the table will look like
Order
order_id 5
order_date '05-06-2020'
CusotmerOrder
customer_order_id 1
order_id 5
type 'M'
customer_order_id 2
order_id 5
type 'S'
and so on
How can I write a qry that will return all unique order_ids that have combination of S and M type customers?
It is easy self join query:
SELECT DISTINCT M.order_id
FROM CustomerOrders AS M
INNER JOIN CustomerOrders AS S
ON M.order_id = S.order_id
WHERE M.customer_type = 'M'
AND S.customer_type = 'S'
You can use exists:
Select distinct order_id
from CustomerOrder co
where exists (select * from CustomerOrder co1
where co.order_id = co1.order_id and co1.Type = 'M') and
exists (select * from CustomerOrder co1
where co.order_id = co1.order_id and co1.Type = 'S');

Select Customers who purchased one specific Product

We have two tables:
Customers:
Products:
The goal is to select [Id] and [CustomerName] of Customers who purchased Milk AND did not purchase Bread. In the case the correct query should return a customer with Id 2 (Ann).
The query which I thought of (and which is obviously incorrect) is:
select CustomerName from dbo.Customers
where Id in
(
select CustomerId from dbo.Products
where ProductName = 'Milk' and ProductName != 'Bread'
)
It returns two customers: 1 (John) and 2 (Ann).
How to rewrite the query so it would return only customer with Id 2?
You can try the query below
SELECT CustomerName
FROM dbo.Customers c
WHERE EXISTS (
SELECT 1
FROM dbo.Products
WHERE CustomerId = c.Id
AND ProductName = 'Milk'
) AND NOT EXISTS (
SELECT 1
FROM dbo.Products
WHERE CustomerId = c.Id
AND ProductName = 'Bread'
)
You don't need to use two exists, just use where clause with not exists :
select c.*
from customer c
where ProductName = 'Milk' and
not exists (select 1 from Products p where p.CustomerId = c.id and p.ProductName = 'Bread');
I am inclined to use aggregation for this. Here is one method:
select c.customerId
from dbo.Products p
where p.productName in ('Milk', 'Bread')
group by c.customerId
having sum(case when p.productName = 'Milk' then 1 else 0 end) > 0 and
sum(case when p.productName = 'Bread' then 1 else 0 end) = 0 ;
You can add the join in to get the customer name, if you really need that.
Basically, this counts the number of rows for each customer that have 'Milk'. The > 0 says there is at least one. It then counts the number of rows that have 'Bread'. The = 0 says that there are none.
SELECT P.Id ,C.Customers
FROM Customers AS C , Product AS P
WHERE (C.Id = P.CustomerId)
AND (P.ProductName = 'Milk')
AND NOT EXISTS (
SELECT 1
FROM Products
WHERE CustomerId = C.Id
AND ProductName = 'Bread'
)
If normalization is not the case, efficiency isn't either. Here you go:
select CustomerName from dbo.Customers
where
Id in (select CustomerId from dbo.Products where ProductName = 'Milk')
and Id not in (select CustomerId from dbo.Products where ProductName = 'Bread')
Ah. Just saw it could be considered a duplicate of Eric's answer. Using exists may be a little faster indeed.

SQL INNER JOIN entity

I want to execute this query :
-- The most expensive item sold ever
SELECT
c.itemID, c.itemName
FROM
item AS c
JOIN
(SELECT
b.itemID as 'itemid', MAX(b.item_initialPrice) AS 'MaxPrice'
FROM
buyeritem AS a
INNER JOIN
item AS b ON a.item_ID = b.itemID) AS d ON c.itemID = d.itemid
GROUP BY
c.itemID, c.itemName;
My item table looks like this:
create table item
(
itemID int IDENTITY(1000, 1) NOT NULL,
itemName varchar(15) NOT NULL,
Item_desc varchar(255),
Item_initialPrice MONEY,
ItemQty int,
ownerID int NOT NULL,
condition varchar(20) NOT NULL,
PRIMARY KEY (itemID),
FOREIGN KEY (ownerID) REFERENCES seller (sellerID)
);
The problem is that column item.itemID is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. I tried to add a group by clause at the end
group by c.itemID, c.itemName
but I still get the same error? I don't really know where the problem comes from.
I also have this query
-- The most active seller(the one who has offered the most number of items)
SELECT
a.ownerID, b.sellerName
FROM
item AS a
INNER JOIN
seller AS b ON a.ownerID = b.sellerID
GROUP BY
a.ownerID, b.sellerName
ORDER BY
COUNT(a.itemID) DESC;
I want to add itemQty along with the ownerID and sellerName from item table stated above, what would be the best way to achieve that?
Just write distinct instead of Group By as Group By will not work with out an aggregated function like sum,max etc. in select statement which is missing in your query.An example of this is second query which I have written
SELECT distinct c.itemID, c.itemName
FROM item AS c
JOIN (
SELECT b.itemID as itemid, MAX(b.item_initialPrice) AS MaxPrice FROM buyeritem AS a
INNER JOIN item AS b ON a.item_ID = b.itemID
GROUP BY b.itemID) as d
ON c.itemID = d.itemid ;
For second query
Select a.* from
(
SELECT a.ownerID, b.sellerName, count(distinct a.ITEM_ID) as item_qty
FROM item AS a
INNER JOIN seller AS b ON a.ownerID = b.sellerID
GROUP BY a.ownerID,b.sellerName
) a
order by item_qty DESC

Confused with sql query

I have the following tables:
Customer(login varchar, town varchar)
Orders (Ordno int , login varchar) >>login Fk from Customer
combination (Id int, ordno int ,Product_Id int) >>ordno fk from orders
I need to show the products that have been sold in ALL the cities.
Example:
Insert into Customer (log1 , NY) (log2, NY) (log3, London)
Insert into Orders (1,log1) (2,log1) (3,log3)
Insert into combination (1,1,1) (2,2,2) (3,3,1)
Product 1 sold in NY
product 2 sold in NY
product 1 sold in London
if the available cities are only NY and London, then the only product that must be the result of the query is product 1
SELECT a.ProductID
FROM Combination a
INNER JOIN Orders b
ON a.OrdNo = b.OrdNo
INNER JOIN Customer c
ON b.Login = c.LogIn
GROUP BY a.ProductID
HAVING COUNT(DISTINCT a.ID) = (SELECT COUNT(DISTINCT town) FROM Customer)
SQLFiddle Demo
Not sure what exactly you are trying to do here.
SELECT c.Town, cc.Product_Id FROM from Customer c
JOIN Orders o ON c.login = o.login
JOIN Combination cc ON o.Ordno = cc.ordNo
GROUP BY c.town
This will group the towns together and show you the Product_Id
You still need a Product table to display the product table.
This query excludes the product table
Assuming Products table looks like this:
Products (Product_Id int, Name)
You need to join stuff all the way down (or up) to customer...
SELECT p.Name, c.town
FROM Products p
INNER JOIN Combination comb ON comb.Product_Id=p.Product_Id
INNER JOIN Orders o ON o.Ordno=comb.ordno
INNER JOIN Customer cust ON cust.login=o.login
GROUP BY p.Name, c.town

sql query with two tables having reference key

I have two tables:
Discounts(disid primary key)
Cust(custid primary key, disid ref discount(disid))
Now I need a query to get custid having all disid(discount coupons) and the customer may contain the same disid more than once.
select custid, count(distinct disid) from cust
group by custid
having count(*) = (select count(*) from discounts)
SELECT COUNT(DISTINCT D.disid) FROM CUST C
INNER JOIN DISCOUNTS D ON D.disid=C.disid GROUP BY D.disid
try either of this solutions:
SELECT a.custid, COUNT(a.disid) totalCoupon
FROM cust a
INNER JOIN discounts b
ON b.disid = a.disid
GROUP BY a.custid
or
SELECT a.custid, COUNT(a.disid) totalCoupon
FROM cust a
INNER JOIN discounts b
ON b.disid = a.disid
GROUP BY a.custid
HAVING COUNT(a.disid) > 1 -- customers having the same (but more than 1)
-- CouponID will only be shown here