Small Issue with Aggregate Functions - sql

I'm having a small problem with an aggregate function that I can't quite crack.
I have to get a count of customers for each representative in my database - I can accomplish this - the second part of my is that I have to only display the representative with the highest number of customers.
So far I have;
SELECT Rep.RepNum, Count(Customer.RepNum) AS [CustomerCount]
FROM Rep INNER JOIN Customer ON Rep.RepNum = Customer.Repnum
GROUP BY Rep.RepNum
I know I'm probably going to have to use a nested query to solve this, but I'm not sure how to go about this problem. It has been fighting me for almost and hour, and ANY help would be greatly appreciated.

Try:
SELECT TOP 1 Rep.RepNum,
Count(Customer.RepNum) AS [CustomerCount]
FROM Rep
INNER JOIN Customer ON Rep.RepNum = Customer.Repnum
GROUP BY Rep.RepNum
ORDER BY COUNT(Customer.RepNum) DESC

Maybe this will do:
SELECT Rep.RepNum, Count(Customer.RepNum) AS [CustomerCount]
FROM Rep INNER JOIN Customer ON Rep.RepNum = Customer.Repnum
GROUP BY Rep.RepNum
HAVING Count(Customer.RepNum) = (
Select max([CustomerCount])
FROM (SELECT Rep.RepNum,
Count(Customer.RepNum) AS [CustomerCount]
FROM Rep INNER JOIN Customer ON Rep.RepNum = Customer.Repnum
GROUP BY Rep.RepNum));

Related

Showing customers who have purchased more than 1 product, but from the same subscription

I'm trying to find the number of customers who have ordered more than one product, with the same subscription.
I've first selected the count of the id_customer from customer. Then joined on subscription and order (on the correct keys). This was done so that I have all the data available to me from all 3 tables. Then grouped by the id_customer to get just the unique customers. And lastly filtered to have a fk_product (products a customer has) greater than 1.
SELECT COUNT(t1.id_customer)
FROM customer t1
INNER JOIN subscription t2 ON t1.id_customer = t2.fk_customer
INNER JOIN order t3 ON t2.id_subscription = t3.fk_subscription
GROUP BY t1.id_customer
HAVING COUNT(t3.fk_product) > 1
I'd like to better understand if this is the correct syntax to obtain the data I'm looking for. Since I have t2.id_subscription and t3.fk_subscription linked, wouldn't this be correct? I'm still getting the wrong output. I'm thinking its perhaps the way I have my scopes, or some subtle aspect of SQL that I'm not using/understanding.
Thank you for your help!!
Use two levels of aggregation. Your data model is a bit hard to follow, but I think:
SELECT COUNT(DISTINCT so.fk_customer)
FROM (SELECT s.fk_customer, s.id_subscription
FROM subscription s
order o
ON s.id_subscription = o.fk_subscription
GROUP BY s.fk_customer, s.id_subscription
HAVING MIN(o.fk_product) <> MAX(o.fk_product)
) so
select count(distinct s.id_customer)
from (
SELECT t1.id_customer
FROM customer t1
INNER JOIN subscription t2 ON t1.id_customer = t2.fk_customer
INNER JOIN order t3 ON t2.id_subscription = t3.fk_subscription
GROUP BY t1.id_customer, t3.fk_subscription
HAVING COUNT(1) > 1
) s

Define sort order when updating

I have a script that updates an ID field on one table where that record matches to another table based on criteria.
Below is the general structure of my query.
update p.saleId = e.saleId
from products p inner join sales s on s.crit1 = p.crit1
where p.someDate between s.startDate and s.endDate
This is working fine. My issue is that in some situations there is more than one match on the 'sales' table with this query which is generally ok. I'd however like to sort these results based on another field to make sure the saleId I get is the one with the highest cost.
Is that possible?
As it is the saleID you want to set and the sales table you are looking up, you can probably just update all products records. Then you can write a simple update statement on the table and don't have to join. This makes this much easier to write:
update products p
set saleId =
(
select top(1) s.saleId
from sales s
where s.crit1 = p.crit1
and p.someDate between s.startDate and s.endDate
order by cost desc
);
The main difference to your statement is that mine sets saleId = NULL where there is no match in the sales table, while your lets these untouched. But I guess that doesn't make a difference here.
I hope the below query may solve. Wrote very high level draft as per your question. Please take only the concept not the syntax.
with maxSales as (select salesId, crit1 from sales s1
where cost = (select max(cost) from
sales s2 where s1.crit1 = s2.crit1)
update products p set p.saleId =
(select s.saleId from
maxSales s
where s.crit1 = p.crit1
and p.someDate between s.startDate and s.endDate)
UPDATE p
set p.saleId = e.rowNumber
FROM products p
INNER JOIN
(SELECT saleId, row_number() OVER (ORDER BY saleId DESC) as rowNumber
FROM sales)
e ON e.saleId = p.saleId
TRY THIS:
UPDATE p
SET p.saleid = s.saleid
FROM products p
INNER JOIN
(SELECT s.crit1,
s.saleid
FROM sales s
WHERE cost IN
(SELECT max(cost) cost
FROM sales
GROUP BY crit1)) s ON s.crit1 = p.crit1
None of the answers worked, but I managed to do it by using and Outer Apply as my join, and specified the sort order in that.
Cheers everyone for the input.

SQL List the representative that handles the most customers

I have 2 tables SALESREP and CUSTOMER
I need to find out which salesrep has most customers
I have the following code:
select rep_lname, count(cust_num)
from customer inner join salesrep
on customer.REP_NUM = SALESREP.REP_NUM
group by rep_lname
This gives me all the rows with the number of customers each salesrep has, instead I need only one row that has the most customers.
How can I find the row with MAX num of customers?
select rep_lname, count(cust_num)
from customer inner join salesrep
on customer.REP_NUM = SALESREP.REP_NUM
group by rep_lname order by count(cust_num) desc limit 1;
I'm sure there's another way using having, but I can't seem to figure it out at the moment. Perhaps somebody else will chime in with it?
SELECT TOP 1 WITH TIES rep_lname, COUNT(cust_num)
FROM customer inner join salesrep
ON customer.REP_NUM = SALESREP.REP_NUM
GROUP BY rep_lname
ORDER BY count(cust_num) DESC

Joining two tables with a queried table

Oh great SQL gods I require your assistance.
Here is my Schema:
CAR(Serial_no,Model,Manufacturer,Price)
OPTIONS(Serial_no,Option_name,Price)
SALE(Salesperson_id,Serial_no,Date,Sale_price)
SALESPERSON(Salesperson_id,Name,Phone)
First, I need to join the CAR and SALE table by Serial_no.
Second, i need to take the OPTIONS table and SUM all the prices for similar Serial_no which the following does:
SELECT O.Serial_no, SUM(O.Price)
FROM OPTIONS O
GROUP BY (O.Serial_no);
Last I need to merge steps one and two and query the result so I get a resulting set of where CAR.Price < (SALE.Sale_price + OPTIONS.Price).
Can this be done? Any help would be immensely appreciated!
Thanks,
Mark
SELECT C.Serial_no,
MIN(c.Price) CarPrice,
MIN(s.Sale_price) SalePrice,
SUM(o.Price) OptionsPrice,
MIN(s.Sale_price) + IFNULL(SUM(o.Price),0) TotalPrice
FROM Car c JOIN Sale s ON c.Serial_no = s.Serial_no
LEFT JOIN `Options` o ON c.Serial_no = o.Serial_no
GROUP BY c.Serial_no
HAVING MIN(c.Price) < MIN(s.Sale_price) + IFNULL(SUM(o.Price),0)
Note: the MIN() are not taking anything away, it is only there since you are grouping, and the options table may have multiple rows.
Another option would be to do the calculations in a Subquery which may lead to better performance:
SELECT C.Serial_no,
C.Price,
S.Sale_price,
og.SumPrice
FROM Car c JOIN Sale s ON c.Serial_no = s.Serial_no
LEFT JOIN (
SELECT Serial_no, SUM(Price) SumPrice
FROM `Options`
GROUP BY Serial_no
) og ON c.Serial_no = og.Serial_no
WHERE c.Price < s.Sale_price + IFNULL(og.SumPrice,0)

Join two tables where all child records of first table match all child records of second table

I have four tables: Customer, CustomerCategory, Limit, and LimitCategory. A customer can be in multiple categories and a limit can also have multiple categories. I need to write a query that will return the customer name and limit amount where ALL the customers categories match ALL the limit categories.
I'm guessing it would be similar to the answer here, but I can't seem to get it right. Thanks!
Edit - Here's what the tables look like:
tblCustomer
customerId
name
tblCustomerCategory
customerId
categoryId
tblLimit
limitId
limit
tblLimitCategory
limitId
categoryId
I THINK you're looking for:
SELECT *
FROM CustomerCategory
LEFT OUTER JOIN Customer
ON CustomerCategory.CustomerId = Customer.Id
INNER JOIN LimitCategory
ON CustomerCategory.CategoryId = LimitCategory.CategoryId
LEFT OUTER JOIN Limit
ON Limit.Id = LimitCategory.LimitId
Updated!
Thanks to Felix for pointing out a flaw in my existing solution (3 years after I originally posted it, hehe). After looking at it again, I think this might be correct. Here I'm getting (1) the customers and limits with matching categories, plus the number of matching categories, (2) the number of categories per customer, (3) the number of categories per limit, (4) I then ensure the number of categories for customer and limits is the same as the number of the matches between the customers and limits:
UNTESTED!
select
matches.name,
matches.limit
from (
select
c.name,
c.customerId,
l.limit,
l.limitId,
count(*) over(partition by cc.customerId, lc.limitId) as matchCount
from tblCustomer c
join tblCustomerCategory cc on c.customerId = cc.customerId
join tblLimitCategory lc on cc.categoryId = lc.categoryId
join tblLimit l on lc.limitId = l.limitId
) as matches
join (
select
cc.customerId,
count(*) as categoryCount
from tblCustomerCategory cc
group by cc.customerId
) as customerCategories
on matches.customerId = customerCategories.customerId
join (
select
lc.limitId,
count(*) as categoryCount
from tblLimitCategory lc
group by lc.limitId
) as limitCategories
on matches.limitId = limitCategories.limitId
where matches.matchCount = customerCategories.categoryCount
and matches.matchCount = limitCategories.categoryCount
I don't know if this will work or not, just a thought i had and i can't test it, I'm sures theres a nicer way! don't be too harsh :)
SELECT
c.customerId
, l.limitId
FROM
tblCustomer c
CROSS JOIN
tblLimit l
WHERE NOT EXISTS
(
SELECT
lc.limitId
FROM
tblLimitCategory lc
WHERE
lc.limitId = l.id
EXCEPT
SELECT
cc.categoryId
FROM
tblCustomerCategory cc
WHERE
cc.customerId = l.id
)