Deleting records that are not joined on in SQL - 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
)

Related

With SqlServer, where * not exists

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

Return customers with no sales

I'm a bit of a beginner with SQL so apologies if this seems trivial/basic. I'm struggling to get my head around it...
I am trying to generate results that show all customers that are in the customer table that have never placed an order and will therefore have no entry on the invoice table.
In other words, I want to select all customers from the customer table where there is no entry for their customer number in the invoice table.
Many thanks,
Mike
SELECT *
FROM customer c
WHERE NOT EXISTS (
SELECT 1
FROM invoice i
WHERE i.customerid = c.customerid
)
I would suggest you also read Oracle's documentation on different types of table joins here.
if customer_id is the collumn that identify the customer you should do something like this...
select * from Customer
where customer_id not in (select customer_id from invoice)
If you want to return all customer rows, then you will want to use a LEFT JOIN
select *
from customer c
left join invoices i
on c.customerid = i.customerid
where i.customerid is null
See SQL Fiddle with Demo
If you need help learning JOIN syntax, then here is a great visual explanation of joins.
A LEFT JOIN will return all rows from the customer table even if there is not a matching row in the invoices table. If you wanted to return only the rows that matched in both tables, then you would use an INNER JOIN. By adding the where i.customerid is null to the query it will return only those rows with no match in invoices.

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

SQL statement to get all customers with no orders

I have a typical Persons table and an Orders table defined in such a way that I can do JOIN query as the following to return Orders for all Persons.
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
INNER JOIN Orders
ON Persons.id=Orders.Person_id
The question is, how do I write a statement that would return all Persons with NO Orders?
I'm using mysql.
Thank all in advance.
You may want to use LEFT JOIN and IS NULL:
SELECT Persons.LastName, Persons.FirstName
FROM Persons
LEFT JOIN Orders ON Persons.id = Orders.Person_id
WHERE Orders.Person_id IS NULL;
The result of a left join always contains all records of the "left" table (Persons), even if the join-condition does not find any matching record in the "right" table (Orders). When there is no match, the columns of the "right" table will NULL in the result set.
This should work... theres more than one way to do it.
select * from persons where person.id not in (select person_id from orders)
Just for completeness, here is the not exists version:
select * from persons p
where not exists
(select null from orders o where o.person_id = p.id)
You can use left join:
SELECT DISTINCT o.CustomerID from Orders as o
left join Customers as c
on o.CustomerID=c.CustomerID
Question
Find customers who have never made an order.
Output the first name of the customer.
Data
Two tables: Customers and Orders
SELECT first_name
from customers
WHERE first_name not in
(select first_name
from customers
join orders on customers.id=orders.cust_id)