I have a query written with 3 CTE's and I need to get the exact same result using only 1 CTE. Can someone help me?
WITH Q1(cid, sumEP) AS
(
SELECT customerid, SUM(Extendedprice)
From "Invoices"
GROUP BY customerid
), Q2(cid, oid, mf) AS
(
SELECT DISTINCT customerid, orderid, freight
FROM "Invoices"
), Q3 AS
(
SELECT cid, SUM(mf) AS smf
FROM Q2
GROUP BY cid
)
SELECT Q1.cid, sumEP + smf AS total
FROM Q1
JOIN Q3 ON Q1.cid = Q3.cid
LIMIT 10
smf is the sum of distinct values of freight per order (for the same customer), but this you can do with sum(distinct freight)
So I would suggest this query:
WITH Q(customerid, orderid, total) AS
(
SELECT customerid, orderid, SUM(Extendedprice) + SUM(DISTINCT freight)
FROM Invoices
GROUP BY customerid, orderid
)
SELECT customerid, SUM(total) AS total
FROM Q
GROUP BY customerid
ORDER BY 2 DESC
LIMIT 10;
When there are no cases where different orders for the same customer have the same freight value, then it can be simplified to:
SELECT customerid, SUM(Extendedprice) + SUM(DISTINCT freight) AS total
FROM Invoices
GROUP BY customerid
ORDER BY 2 DESC
LIMIT 10
Note I added an order by so that you limit the results with some logic behind it -- in this case getting the top-10 by total. Change as needed.
Related
Let's say I have three tables to manage purchases from my online shop:
Products: with columns ID, Name, Price
Customers: with columns ID, Name
Purchases: with columns ProductID, CustomerID, PurchaseDate
Now, how would I go about retrieving products purchased by more than N distinct customers?
I've tried the following on SQL Server 2019 Trial Edition but I'm getting a syntax error on COUNT.
SELECT ProductID, CustomerID, COUNT(*) as C
FROM Purchases
GROUP BY ProductID, CustomerID
HAVING C > 100
ORDER BY C DESC
Better still, how would I go about retrieving products purchased by more than N distinct customers over a 30-day period?
Thanks for any help and/or pointers.
With your current query, you are just counting how often each customer bought each product, because you are grouping by the combination of productid and customerid. Furthermore you cannot reference to the column alias for the count in the HAVING or ORDER BY clause
Try this
declare #purchasedatelower datetime = dateadd(day, -30, getdate())
declare #purchasedateupper datetime = getdate()
declare #distinctcustomers int = 100
select productid, count(distinct customerid) as customercount
from purchases
where purchasedate between #purchasedatelower and #purchasedateupper
group by productid
having count (distinct customerid) >= #distinctcustomers
order by count(distinct customerid) desc
This will return all products, which have been bought by at least 100 distinct customers, in the last 30 days, together with the distinct number of customers.
Try to order them by COUNT()
SELECT ProductID, CustomerID
FROM Purchases
GROUP BY ProductID, CustomerID
HAVING COUNT(*) > 100
ORDER BY COUNT(*) DESC
Now, how would I go about retrieving products purchased by more than N distinct customers?
You would use COUNT(DISTINCT):
SELECT ProductID, COUNT(DISTINCT CustomerID) as num_customers
FROM Purchases
GROUP BY ProductID
HAVING COUNT(DISTINCT CustomerID) > 100
ORDER BY COUNT(DISTINCT CustomerID) DESC;
If you have a particular period in mind, then add a WHERE clause before the GROUP BY.
DECLARE #Popularity int = 1
DECLARE #MonthsAgo int = 1
SELECT p.ProductId, p.ProductName, pc.CustomersDistinct
FROM (
-- Sub-query to compute the aggregate.
-- Count the number of distinct customers that purchased each product.
SELECT ProductId, COUNT(DISTINCT CustomerId) AS CustomersDistinct
FROM Purchases
WHERE PurchaseDate >= DATEADD(MONTH, -#MonthsAgo, CURRENT_TIMESTAMP)
GROUP BY ProductId
HAVING COUNT(DISTINCT CustomerId) > #Popularity
) AS pc
-- Now do JOINs to look up helpful values for the final SELECT list.
INNER JOIN Products p ON pc.ProductId = p.ProductId
ORDER BY 3 DESC
My problem is that:
Create a view that shows the top 5 selling products as well as an aggregated row that shows the total sales for all other products and a Grand total row that sums all of the above.
WITH ProductTop5 AS
(
SELECT [dbo].[Product].[ProductName] AS ProductName, SUM([dbo].[SalesOrderDetail].[LineTotal]) AS TotalAmount
FROM [dbo].[Product]
JOIN [dbo].[SalesOrderDetail] ON [dbo].[Product].[ProductID] = [dbo].[SalesOrderDetail].[ProductID]
GROUP BY [dbo].[Product].[ProductName]
)
You could use ROW_NUMBER/RANK to calculate ranking of product:
WITH Product AS
(
SELECT p.[ProductName] AS ProductName,
SUM(sod.[LineTotal]) AS TotalAmount
FROM [dbo].[Product] p
JOIN [dbo].[SalesOrderDetail] sod
ON p.[ProductID] = sod.[ProductID]
GROUP BY p.[ProductName]
), ProductWithRank AS (
SELECT ProductName, Total_Amount,
ROW_NUMBER() OVER(ORDER BY Total_Amount DESC) AS rn
FROM Product
)
SELECT ProductName, TotalAmount
FROM ProductWithRank
WHERE rn <= 5
UNION ALL
SELECT 'All Others', SUM(Total_Amount)
FROM ProductWithRank
WHERE rn > 5
UNION ALL
SELECT 'Grand Total', SUM(TotalAmount)
FROM ProductWithRank;
I have table called Orders. There are three columns: CustomerID, ProductGroup, Size.
How can I get TOP selling size by ProductGroup from this table?
I can do it 1 by 1 with
SELECT TOP 1 Count(customerid) as customers, ProductGroup, Size
FROM Orders
WHERE ProductGroup = xxx
GROUP BY ProductGroup, Size
ORDER BY Count(customerid) DESC
However, I would like to get full list at once.
Not sure, but it may help you.
Declare #temp table(CustomerID int, ProductGroup varchar(10), Size int)
insert into #temp
Select 1,'ABC',15 union all
Select 2,'ABC',10 union all
Select 3,'XYZ',12 union all
Select 4,'ABC',15 union all
Select 3,'XYZ',12 union all
Select 3,'XYZ',12 union all
Select 3,'XYZ',15 union all
Select 3,'XYZ',11 union all
Select 3,'XYZ',12
Select * from (
Select RANK() Over(PARTITION BY ProductGroup order by customers desc) RankVal,customers,ProductGroup, Size
from (
SELECT Count(CustomerID) as customers, ProductGroup, Size
FROM #temp
GROUP BY ProductGroup, Size
) T
)T1
WHERE RankVal = 1
Please check following SELECT query with SQL Count using Partition By clause
;with cte as (
SELECT
Distinct ProductGroup, Size,
COUNT(*) OVER (Partition By ProductGroup, Size) cnt
FROM Customers
)
select
ProductGroup, Size, cnt
from (
select *,
rn = ROW_NUMBER() OVER (Partition By ProductGroup Order By cnt desc)
from cte
) t
where rn = 1
You want to have the top selling product for every ProductGroup. The way to achieve this, is to use a group by, e.g. via
SELECT ProductGroup, MAX(size)
FROM orders
GROUP BY ProductGroup
This way you get a result table with one column per ProductGroup and the maximum of the sizes by this product group.
You can use the aggregate function max() to select the highest size and group it according to ProductGroup.
SELECT COUNT(customerid) as customers, ProductGroup, MAX(Size) FROM
Orders WHERE Size IN (SELECT MAX(Size) FROM Orders) GROUP BY ProductGroup
ORDER BY customerid DESC;
Note that this query has not been tested yet and I wonder if why do you need to get the count of customerid if your selecting only the highest Size per ProductGroup.
You can try to use the MAX operator and put your SQL in a subquery, like this (not tested):
SELECT MAX(customers), ProductGroup, Size FROM Orders GROUP BY ProductGroup, Size HAVING MAX(customers) =
SELECT MAX(customers) AS myMax FROM (
SELECT Count(customerid) as customers, ProductGroup, Size
FROM Orders
GROUP BY ProductGroup, Size) AS O
GROUP BY ProductGroup, Size
How do i combine a SUM and MAX in a single query?
Lets say i have a orderrule:
ProductID \ Quantity
I Could say:
Select ProductID,SUM(Quantity) AS Sold
FROM Orderrule
GROUP BY ProductID
ORDER BY SUM(Quantity) Desc
However that would return all sales, and not just the most sold product (with quantity).
Try this
SELECT TOP(1)
*
FROM
(
Select
ProductID,
MAX(Quantity) As MaxQuantity,
SUM(Quantity) AS Sold
FROM Orderrule
GROUP BY ProductID
)AS X
ORDER BY Sold DESC
So there are two ways to do it - first to have a limit on the number of results, something likes:
select * from (your_select) where rownum = 1
the other one is to pick the one with the the highest value, which will require a subselect, something like:
having sum(quantity) =
(select max(sum_quan) from (select sum(Quantity) from orderrule group by Product_id))
SELECT TOP 1 ProductID, Sold FROM
(
SELECT ProductID, SUM(Quantity) AS Sold
FROM Orderrule
GROUP BY ProductID
) totals
ORDER BY Sold DESC
Have a query that shows this...
salesPersonId Total
------------- -----------
AB4 3
GT10 2
JB9 1
JS1 2
KT8 4
TC3 4
VG7 2
WC2 7
(8 row(s) affected)
My query is...
SELECT so.salesPersonId, COUNT(so.orderId) AS 'Total'
FROM salesOrder AS so
GROUP BY so.salesPersonId
GO
I wanted to do this...
SELECT so.salesPersonId, COUNT(so.orderId) AS 'Total'
FROM salesOrder AS so
WHERE MAX(COUNT(so.orderId))
GROUP BY so.salesPersonId
GO
This gives me an error, any ideas on how to show only the salesPersonId with the highest total? Here being WC2.
You can use a common table expression (or a subquery) to get the breakdown and then select all entries in your CTE where their total is equal to max total (as there may be more than one):
;WITH TotalOrders
AS
(
SELECT so.salesPersonId, COUNT(so.orderId) AS 'Total'
FROM salesOrder AS so
GROUP BY so.salesPersonId
)
SELECT *
FROM TotalOrders [TO]
WHERE [TO].Total = (SELECT MAX([TO].Total) FROM TotalOrders [TO])
WITH totalCount
AS
(
SELECT so.salesPersonId, COUNT(so.orderId) AS 'Total'
FROM salesOrder AS so
GROUP BY so.salesPersonId
),
maxCount AS
(
SELECT salesPersonId, Total,
DENSE_RANK() OVER (ORDER BY Total DESC) rn
FROM totalCount
)
SELECT salesPersonId, Total
FROM maxCount
WHERE rn = 1