Reputation: 1861
Let's say I have three tables - Orders, OrderDetails, and ProductType - and the Orders table includes a column for Customer. What I need to do is write a query that will show me a list of customers and how many orders each customer has placed, as well as displaying and grouping by another column, which is a boolean based on whether a particular type of product - say, telephones - is in the order.
For example, we might have:
Customer | NumOrders | IncludesPhone
---------------------------------
Jameson | 3 | Yes
Smith | 5 | Yes
Weber | 1 | Yes
Adams | 2 | | No
Jameson | 1 | No
Smith | 7 | No
Weber | 2 | No
However, when I try to write the query for this, I'm getting multiple rows with the same values for Customer and IncludesPhone, each with a different value for NumOrders. Why is this happening? My query is below:
SELECT Customer, COUNT(Customer) AS NumOrders, CASE WHEN (ProductType.Type = 'Phone') THEN 'Yes' ELSE 'No' END AS IncludesPhone
FROM Orders INNER JOIN OrderDetails INNER JOIN ProductType
GROUP BY Customer, Type
Order By IncludesPhone, Customer
Upvotes: 0
Views: 63
Reputation: 1
You could try this query:
SELECT x.Customer,x.NumOrders,
CASE WHEN x.NumOrders>0 AND EXISTS(
SELECT *
FROM Orders o
INNER JOIN OrderDetails od ON ...
INNER JOIN ProductType pt ON ...
WHERE o.Customer=x.Customer
AND pt.Type = 'Phone'
) THEN 1 ELSE 0 END IncludesPhone
FROM
(
SELECT Customer,COUNT(Customer) AS NumOrders
FROM Orders
GROUP BY Customer
) x
Order By IncludesPhone, x.Customer;
or this one:
SELECT o.Customer,
COUNT(o.Customer) AS NumOrders,
MAX(CASE WHEN EXISTS
(
SELECT *
FROM OrderDetails od
JOIN ProductType pt ON ...
WHERE o.OrderID=od.OrderID -- Join predicated between Orders and OrderDetails table
AND ProductType.Type = 'Phone'
) THEN 1 ELSE 0 END) AS IncludesPhone
FROM Orders o
GROUP BY Customer
ORDER BY IncludesPhone, o.Customer
Upvotes: 0
Reputation: 776
This query should work
SELECT Customer, COUNT(Customer) AS NumOrders,
CASE WHEN (ProductType.Type = 'Phone') THEN 'Yes' ELSE 'No' END AS IncludesPhone
FROM Orders INNER JOIN OrderDetails INNER JOIN ProductType
GROUP BY Customer,
CASE WHEN (ProductType.Type = 'Phone') THEN 'Yes' ELSE 'No' END
Order By IncludesPhone, Customer
Upvotes: 1
Reputation: 166336
Change the group by to
GROUP BY Customer,
CASE WHEN (ProductType.Type = 'Phone') THEN 'Yes' ELSE 'No' END
Upvotes: 2
Reputation: 117337
That's because you're grouping by Type
column, so there could be duplicate rows. For example, for types 'Email' and 'Personal' column IncludesPhone
will be 'No', but as you're grouping by Type
there would be two records in the output.
To fix this, you can use same expression in the group by
clause or use subquery or Common Table Expression:
with cte as (
select
Customer,
case when pt.Type = 'Phone' then 'Yes' else 'No' end as IncludesPhone
from Orders as o
inner join OrderDetails as od -- ???
inner join ProductType as pt -- ???
)
select Customer, IncludesPhone, count(*) as NumOrders
from cte
group by Customer, IncludesPhone
order by IncludesPhone, Customer
using same expression in the group by
clause:
select
Customer,
case when pt.Type = 'Phone' then 'Yes' else 'No' end as IncludesPhone,
count(*) as NumOrders
from Orders as o
inner join OrderDetails as od -- ???
inner join ProductType as pt -- ???
group by Customer, case when pt.Type = 'Phone' then 'Yes' else 'No' end
Upvotes: 0
Reputation: 10680
Since you're grouping on both Customer
and Type
, your query returns the count of orders per customer per type. If you only want one row per customer, you should only group by Customer
, and then use something like this, to determine whether a given customer bought a phone:
SELECT Customer, COUNT(Customer) AS NumOrders,
CASE
WHEN SUM(CASE WHEN (ProductType.Type = 'Phone') THEN 1 ELSE 0 END) > 0
THEN 'Yes'
ELSE 'No' END AS IncludesPhone
FROM Orders INNER JOIN OrderDetails INNER JOIN ProductType
GROUP BY Customer
Order By IncludesPhone, Customer
The inner sum basically counts the number of phones bought per customer. If this is more than 0, then the customer bought at least one phone and we return "Yes".
Upvotes: 0