SQL COUNT function for results "greater than or equal to" - sql

I currently have a query where it returns the total number of accounts each customer holds, but how do I make it so that it returns only customers who has more than 1 account?
SELECT C.customerID, COUNT(O.accNumber) AS "total"
FROM Customer C, Owns O
WHERE C.customerID = O.customerID
GROUP BY C.customerID

The answer to your question is HAVING. However, you need to learn to use properJOIN syntax. Simple rule: Never use a comma in the FROM clause. Always use explicit JOIN syntax.
SELECT C.customerID, COUNT(O.accNumber) AS total
FROM Customer C JOIN
Owns O
ON C.customerID = O.customerID
GROUP BY C.customerID
HAVING COUNT(*) > 1;
Actually, you don't even need the JOIN:
SELECT o.customerID, COUNT(o.accNumber) AS total
FROM Owns o
GROUP BY o.customerID
HAVING COUNT(*) > 1;
That's much simpler.

Add a HAVING clause
SELECT C.customerID, COUNT(O.accNumber) AS "total"
FROM Customer C, Owns O
WHERE C.customerID = O.customerID
GROUP BY C.customerID
HAVING COUNT(*) > 1

Please try
WHERE C.customerID = O.customerID AND count(O.accNumber) > 1

Related

SQL - List all customers that we did not make a sale to in the year 1996

This is my functioning SQL query to return the customers that we sold to in 1996:
SELECT C.CustomerID, C.CompanyName
FROM Customers C, Orders O
WHERE C.CustomerID = O.CustomerID AND YEAR(O.OrderDate) = 1996
GROUP BY C.CustomerID, C.CompanyName
ORDER BY C.CustomerID
Now I'm trying to show the opposite; return all customers that we did not sell to in 1996 (even if we did sell to them in other years). This is what I have, however it returns both the customers we didn't sell to in 1996 but also the ones we did:
SELECT C.CustomerID, C.CompanyName FROM Orders O JOIN Customers C
ON O.CustomerID = C.CustomerID
WHERE YEAR(O.OrderDate) != 1996
GROUP BY C.CustomerID, C.CompanyName
ORDER BY C.CustomerID
You can use a correlated subquery that gets the orders from 1996 of a customer with NOT EXISTS.
SELECT c.customerid,
c.companyname
FROM customers c
WHERE NOT EXISTS (SELECT *
FROM orders o
WHERE o.customerid = c.customerid
AND o.orderdate >= '1996-01-01'
AND o.orderdate < '1997-01-01');
Note that you better shouldn't use year() on orderdate as this can prevent indexes form being used, so slowing down the query.
We can build on your existing query and use the left join antipattern:
SELECT C.CustomerID, C.CompanyName
FROM Customers C
LEFT JOIN Orders O
ON C.CustomerID = O.CustomerID
AND O.OrderDate >= '1996-01-01'
AND O.OrderDate < '1997-01-01'
WHERE O.CustomerID IS NULL
ORDER BY C.CustomerID
This phrases as : try to join each customers with the orders they have placed in 1996, and filter on those without any order.
Side note:
always use explicit, standard join (with the ON keyword); old-school, implicit joins should be avoided (no comma in the FROM clause)
as also commented by sticky bit (whose answer is valid and I upvoted it), using date comparison is better form performance than relying on date functions
try this
SELECT C.CustomerID, C.CompanyName FROM Customers C
WHERE
not exists(select 1 FROM Orders O where O.CustomerID = C.CustomerID and YEAR(O.OrderDate) = 1996)
ORDER BY C.CustomerID

COUNT with LEFT JOIN

Two tables named Sales.Customers and Sales.Orders.
Sales.Customers has a foreign key relationship to a column
named CustomerID in Sales.Orders.
Requirement: A query that returns all the customers. The query must also return the number of orders that each customer placed.
Query 1:
SELECT cust.cutomername,
NumberofOrders= COUNT(ord.OrderID)
FROM Sales.Customers Cust
LEFT JOIN
Sales.Orders Ord
ON Cust.CustomerID=Ord.OrderID
GROUP BY
Cust.CutomerName;
But I'm thinking of below one also,
Query2:
SELECT cust.cutomername,
NumberofOrders= COUNT(Cust.cutomerID)
FROM Sales.Customers Cust
LEFT JOIN
Sales.Orders Ord
ON Cust.CustomerID=Ord.OrderID
GROUP BY
Cust.CutomerName;
From both which one do you recommend & why?
This query:
SELECT c.customername, COUNT(o.OrderID)
FROM Sales.Customers c LEFT JOIN
Sales.Orders o
ON c.CustomerID = o.OrderID
GROUP BY c.CustomerName;
Probably returns all customers with meaningless counts -- probably 0 except for OrderIDs that happen to match CustomerIDs.
You probably intend:
SELECT c.customername, COUNT(o.OrderID)
FROM Sales.Customers c LEFT JOIN
Sales.Orders o
ON c.CustomerID = o.CustomerId
GROUP BY c.CustomerName;
In this query, the COUNT() is counting the number of matching orders. It can take the value of 0 for customers with no orders.
For this query:
SELECT c.customername, COUNT(c.OrderID)
FROM Sales.Customers c LEFT JOIN
Sales.Orders o
ON c.CustomerID = o.CustomerID
GROUP BY c.CustomerName;
The COUNT() is returning the number of rows. Every customer has at least one row, so the value would never be 0. Normally, you want the previous query.
Maybe this is your solution:
select c.Customername,
NumberOfOrders = (select count(o.OrderID) from Sales.Orders o where o.CustomerID = c.CustomerID)
from Sales.Customers c
order by c.Customername

Why this LEFT OUTER JOIN is not including all the Primary Keys from the Left

The customers table has total 1000 customers of which 1500 placed orders in FY 2016. But we want to display all the customers with their total number of orders in FY 2016 whether a customer placed an order in that FY or not. But the following query in SQL Server 2012 is displaying only 1490.
What we may be missing here?
SELECT c.CustomerID, count(*) AS TotalOrders
FROM Customers c
LEFT JOIN Orders o ON c.CustomerID = o.CustomerID
WHERE o.FiscalYear = '2016'
GROUP BY c.CustomerID
UPDATE:
The following query returns only 1 more record (1491) - still missing 9 more records.
SELECT c.CustomerID, count(*) AS TotalOrders
FROM Customers c
LEFT JOIN Orders o ON c.CustomerID = o.CustomerID
AND o.FiscalYear = '2016'
GROUP BY c.CustomerID
You where clause is turning the left outer join into an Inner join.
Change it to AND:
SELECT c.CustomerID, count(o.CustomerID) AS TotalOrders
FROM Customers c
LEFT JOIN Orders o
ON c.CustomerID = o.CustomerID
AND o.FiscalYear = '2016' -- Here
GROUP BY c.CustomerID
The correct SQL is:
SELECT c.CustomerID, count(o.CustomerID) AS TotalOrders,
sum(count(o.CustomerID)) over () as TotalTotalOrders
FROM Customers c LEFT JOIN
Orders o
ON c.CustomerID = o.CustomerID AND o.FiscalYear = '2016'
GROUP BY c.CustomerID;
TotalTotalOrders should be all the orders (or at least the ones with valid customer ids).
This will list all customers, whether or not they have any orders regardless of the year in which the order was placed. The sum will then count all orders that were placed in 2016, ignore the rest, and return an intenger (i.e. it will never be null).
SELECT
c.CustomerID
,sum(case when o.FiscalYear = '2016' then 1 else 0 end) AS TotalOrders
FROM Customers c
LEFT JOIN Orders o
ON c.CustomerID = o.CustomerID
GROUP BY c.CustomerID

SQL TOP 1 Syntax for a nested query

New to SQL Server and I am trying to use top 1 to get the company with the most order in my DB within my code that is already working but I don't know how to use it properly. Only missing syntax I think.
Query #1 is working fine:
SELECT
c.CompanyName, COUNT(DISTINCT OrderID) as Nombre_Commande
FROM
Orders O
INNER JOIN
Customers C ON O.CustomerID = c.CustomerID
GROUP BY
c.CompanyName
What I am trying to do
SELECT TOP (1) *
FROM
(SELECT
c.CompanyName, COUNT(DISTINCT OrderID) AS Nombre_Commande
FROM
Orders O
INNER JOIN
Customers C ON O.CustomerID = c.CustomerID
GROUP BY
c.CompanyName)
You need to give the derived table an alias, and also, specifying top without an order by clause is pretty pointless as rows are returned as a set without any order unless the order is explicitly specified with an order by clause:
SELECT TOP (1) *
FROM (
SELECT c.CompanyName, COUNT(DISTINCT OrderID) as Nombre_Commande
FROM Orders O
INNER JOIN Customers C ON O.CustomerID=c.CustomerID
GROUP by c.CompanyName
) AS YourTable
ORDER BY something_meaningful_maybe_nombre_commande?
How about this?
SELECT TOP 1 c.CompanyName, COUNT(DISTINCT OrderID) as Nombre_Commande
FROM Orders O INNER JOIN
Customers C
ON O.CustomerID = c.CustomerID
GROUP by c.CompanyName
ORDER BY Nombre_Commande DESC;
This assumes that Nombre_Commande is what you want to order by.
By the way, I would be surprised if COUNT(DISTINCT) were really needed for this query. COUNT(*) or COUNT(OrderId) should be sufficient.

List Customers That Purchased Orders > The Average Paid Order

The following is my query:
select c.cust_lname, c.cust_fname, o.amount
from CUSTOMER c, orders o
where o.amount >
(select AVG (o.amount)
from orders o
group by order_num
having o.amount > AVG(o.amount));
Why is this not working?
The way you are writing the query, it would look like:
select c.cust_lname, c.cust_fname, o.amount
from CUSTOMER c join
orders o
on c.customerId = o.customerId
where o.amount > (select AVG (o.amount)
from orders o)
Note that you need to join together the two tables to get what you want.
You overengineered it. Take the having clause out of your subquery.
select c.cust_lname, c.cust_fname, o.amount
from CUSTOMER c, orders o
where o.amount >
(select AVG (amount) from orders );