With SqlServer, where * not exists - sql

I got two tables, Orders with two columns as orderid and customerid, and Customers with two columns as customerid and location.
What I'd like to do is find all the customerid in the table Customers, which are not in Orders. For example, Customers.customerid = {A, B, C, D}, Orders.customerid = {A, B, C}, guess what I need to do is just get the ones from Customers but not exists in Orders. For achieving that, I put,
select customerid from Customers where customerid not exists (select customerid from Orders)
But it returns nothing.. My logic is quite simple like, first got all customerid in table Orders, then get the ones which doesn't exisit in the customerIds from table Orders. I can't see why this is wrong..
I tried this later, and it works. May anyone can help me pls?
select customerid from Customers as c where customerid not exists(select customerid from orders as o where c.customerid = o.customerid)
Why do I have to add c.customerid = o.customerid?

Why do I have to add c.customerid = o.customerid?
Because just because you're using the same name for two columns in your database, that doesn't mean that any specific relationship is enforced or assumed between them.
You need to add the c.customerid = o.customerid to specify that you're interested in the specific condition that these two columns are equal.
But any other correlation condition is also allowed by the language. E.g. you could write a query:
select customerid from Customers as c where not exists(
select customerid from Customers as c2 where c2.customerid < c.customerid)
Which would find you the "first" customer, if considering the customers sorted by their customerid values (not that this is the best way of writing this query, it's just a demonstration of the flexibility)
Your first query was, in effect "give me all rows from the Customer table, provided that no rows exist in the Order table" - which is also a perfectly valid thing to ask for, but wasn't what you intended - you intended to perform some form of correlation, which is what you did in your second query.

May be you need:
select customerid from Customers where customerid not in (select customerid from Orders)

Try below query :
SELECT customerid from Customers C WHERE NOT EXISTS
(
SELECT 1 FROM orders O WHERE C.customerid = O.customerid
)

what you need is
select c.customerid from customer c inner join order o on c.customerid = o.customerid where c.customerid not in (select od.customerid from order od)
you can't access data of 2 tables without joining them.

The syntax is a bit off. You mean to write it like this:
SELECT C.CustomerID
FROM Customers C
WHERE NOT EXISTS
(
SELECT O.CustomerID
FROM Orders O
WHERE O.CustomerID = C.CustomerID
)
;
You could also do this with NOT IN, as such:
SELECT customerid
FROM Customers
WHERE customerid NOT IN
(
SELECT customerid
FROM Orders
)
;
The two are semantically equivalent, for the most part.
Some people will probably tell you that you could do the same thing with a LEFT JOIN / IS NULL construct, but you can look at this article to see why that is a poorer choice in many circumstances.

#Damien_The_Unbeliever gave correct explanation and u need to try like this
with some data i created for 2 tables
CREATE TABLE #Orders
(orderid varchar(10), customerid varchar(10))
insert into #Orders values
('venkat','a'),
('raj','b'),
('mahes','c')
CREATE TABLE #Customers
(customerid varchar(10), [location] varchar(10))
insert into #Customers values
('a','and'),
('b','bar'),
('c','board'),
('D','board1')
SELECT cu.customerid from #Customers CU WHERE NOT EXISTS
(
SELECT 1 FROM #orders b WHERE Cu.customerid = b.customerid
)
output
customerid
D

Related

Write Query Based on Two Tables That Returns Number of Orders From Each Customer Grouped by Email

I'm trying to write a query that considers the following tables that will return the number of orders submitted by each customer, grouped by their email.
Ex: john.smith#email.com | 23
Tables
This is what I have so far:
SELECT COUNT(Order ID), Customer.Customer email
FROM Orders
INNER JOIN Customer ON Customer.Customer ID = Orders.Customer ID
GROUP BY Customer.Customer email
ORDER BY COUNT(Order ID)
I'm really struggling with SQL JOINS. Can anyone help me grasp this?
You have a customer table where each row refers to a specific customer.
You have an order table where a customer can have multiple orders.
When you join these two tables, that is, each row of the customer table is joined to each row of the order table that has a single customer ID.
For example, if a customer has two orders, he will be linked to the order table twice. Your table has a one-to-many relationship.
SELECT C.CustomerID, COUNT(*) FROM Customers C, Orders O
WHERE C.CustomerID = O.CustomerID
GROUP BY C.CustomerID
I tried the above query in this website and looks like it worked.
I believe that in your case you'll need to change the C.CustomerID of the SELECT and the GROUP BY to your email like C.email
SELECT C.CustomerEmail, COUNT(*) FROM Customers C, Orders O
WHERE C.CustomerID = O.CustomerID
GROUP BY C.CustomerEmail
If your Customer table allows that the same email can be from multiple IDs, you're going to have some consistency problems in this report.

Why should I join two columns when I can do it in an easier way?

So think that we’ve got two tables and in one of them, we’ve got our customers and the other has our orders in it and we’ve got a customer id in both of them.
So I want to get the orders of a specific customer and in here I’ve got two ways to do it:
I can say (Select * from orders where id = ‘1’
I can say (Select * from customers join orders on id = customers.id where id = ‘1’
So I’m asking this, why should I use the second method as it’s longer to write or are there any other uses to this?
If you have the customer id, then simply do:
select o.*
from orders o
where o.customer_id = 1;
You only need to join the tables together if you want to use other information, such as:
select o.*
from orders o join
customers c
on o.customer_id = c.customer_id
where c.email = #email;

Deleting records that are not joined on in SQL

I have a SQL Server 2008 database. This database has two related tables: Customer and Order. My tables look like this:
Customer
--------
ID
FirstName
LastName
Order
-----
ID
CustomerID
Amount
ShipDate
I need to delete all customers that do NOT have any orders. I cannot figure out the best way to do this. Can someone tell me how to do this? the NOT part is what keeps getting me. Originally I was using "IN" but it's stumping me.
Thank you for your help!
Rather than using the IN operator, use a subquery and NOT EXISTS, something like:
DELETE Customers
FROM Customers c
WHERE NOT EXISTS (
SELECT 1
FROM Orders o
WHERE o.CustomerID = c.ID
)
DELETE Customer
WHERE ID IN
(
SELECT Customer.ID
FROM Customer
LEFT JOIN Order ON
Customer.ID = ORder.CustomerID
WHERE ORder.CustomerID IS NULL
)
Delete from Customer
WHERE ID in
(
SELECT C.ID
FROM Customer C
Left Outer Join Order O ON C.ID = O.CustomerId
WHERE O.ID IS NULL
)

SQL query for join with condition

I have these two tables:
Customers: Id, Name
Orders: Id, CustomerId, Time, Status
I want to get a list of customers for which the LAST order does not have a status of 'Wrong'.
I know how to use a LEFT JOIN to get a count of orders for each customer, but I don't know how I can use this statement for what I want. Maybe a JOIN is not the right thing to use too, I'm not sure.
It's possible that customers do not have any order, and they should be returned.
I'm abstracting the real tables here, but the scenario is for a windows phone app sending notifications. I want to get all clients for which their last notification does not have a 'Dropped' status. I can sort their notifications (orders) by the 'Time' field. Thanks for the help, while I continue experimenting with subqueries in the where clause.
Select ...
From Customers As C
Where Not Exists (
Select 1
From Orders As O1
Join (
Select O2.CustomerId, Max( O2.Time ) As Time
From Orders As O2
Group By O2.CustomerId
) As LastOrderTime
On LastOrderTime.CustomerId = O1.CustomerId
And LastOrderTime.Time = O1.Time
Where O1.Status = 'Dropped'
And O1.CustomerId = C.Id
)
There are obviously alternatives based on the actual database product and version. For example, in SQL Server one could use the TOP command or a CTE perhaps. However, without knowing what specific product is being used, the above solution should produce the results you want in almost any database product.
Addition
If you were using a product that supported ranking functions (which database product and version isn't mentioned) and common-table expressions, then an alternative solution might be something like so:
With RankedOrders As
(
Select O.CustomerId, O.Status
, Row_Number() Over( Partition By CustomerId Order By Time Desc ) As Rnk
From Orders As O
)
Select ...
From Customers
Where Not Exists (
Select 1
From RankedOrders As O1
Where O1.CustomerId = C.Id
And O1.Rnk = 1
And O1.Status = 'Dropped'
)
Assuming Last order refers to the Time column here is my query:
SELECT C.Id,
C.Name,
MAX(O.Time)
FROM
Customers C
INNER JOIN Orders O
ON C.Id = O.CustomerId
WHERE
O.Status != 'Wrong'
GROUP BY C.Id,
C.Name
EDIT:
Regarding your table configuration. You should really consider revising the structure to include a third table. They would look like this:
Customer
CustomerId | Name
Order
OrderId | Status | Time
CompletedOrders
CoId | CustomerId | OrderId
Now what you do is store the info about a customer or order in their respective tables ... then when an order is made you just create a CompletedOrders entry with the ids of the 2 individual records. This will allow for a 1 to Many relationship between customer and orders.
Didn't check it out, but something like this?
SELECT c.CustmerId, c.Name, MAX(o.Time)
FROM Customers c
LEFT JOIN Orders o ON o.CustomerId = c.CustomerId
WHERE o.Status <> 'Wrong'
GROUP BY c.CustomerId, C.Name
You can get list of customers with the LAST order which has status of 'Wrong' with something like
select customerId from orders where status='Wrong'
group by customerId
having time=max(time)

Problem in sql query

I have two tables called customer and items.
With single query I want to get all the custid and customername whose custid='Custid1' and itemid whose custid='Custid1'.
How can I build this query?? custid is the primary key of customer table. custid is the foreign key of items table.
I have written this query its not listing all the custid, only listing custid thrice... Here is my query:
create procedure spGetCustomer
as
begin
select a.custid, a.custname,b.itemid
from customer a inner join items b on a.custid = b.custid
WHERE b.custid='custid1'
end
Your question isn't quite clear - what is it you really want??
The JOIN you have will list all customers with items where the customer.custid is custid1. But that doesn't seem to be what you're looking for.....
Could it be you're looking for all customers - with or without items - that have a specific custid?? Try something like this:
SELECT
c.custid, c.custname, i.itemid
FROM
dbo.customer c
LEFT OUTER JOIN
dbo.items i ON c.custid = i.custid
WHERE
c.custid = 'custid1'
If the items.custid is indeed a foreign key into the customer table, there shouldn't be any items around that have custid = custid1 that aren't joined to an existing customer.
If your question actually relates to how you pass the parameter in, your proc should be:
create procedure spGetCustomer(#custid1 varchar(100))
as
begin
select a.custid, a.custname,b.itemid
from customer a inner join items b on a.custid = b.custid
WHERE b.custid=#custid1
end