SQL values for min and max rows in one row - sql

I have a table with price changes and I need to get initial price and latest price.
In other words I want to display price values for min(StartDate) and max(StartDate) in one row for each product.
Table structure is simple:
ProductID, StartDate, Price
Desired result is
ProductId, StartDate, InitialPrice, LatestDate, LatestPrice

WITH latestPrice AS
(
SELECT ProductID, StartDate, Price,
ROW_NUMBER() OVER (PArtition BY ProductID ORDER BY StartDate DESC) rn
FROM TableName
)
, initalPrice AS
(
SELECT ProductID, StartDate, Price,
ROW_NUMBER() OVER (PArtition BY ProductID ORDER BY StartDate ASC) rn
FROM TableName
)
SELECT a.ProductID,
b.StartDate,
b.Price InitalPrice,
c.StartDate LatestDate,
c.Price LatestPrice
FROM (SELECT DISTINCT ProductID FROM tableName) a
INNER JOIN initalPrice b
ON a.ProductID = b.ProductID AND b.rn = 1
INNER JOIN latestprice c
ON a.ProductID = c.ProductID AND c.rn = 1
SQLFiddle Demo

(SELECT x.ProductId, x.MinStartDate, x.MinPrice, y.MaxStartDate, y.MaxPrice FROM (SELECT a.ProductId, a.MinStartDate, b.Price AS MinPrice FROM (SELECT ProductId, MIN(StartDate) AS MinStartDate FROM Products GROUP BY ProductId) a INNER JOIN Products b ON a.ProductId = b.ProductId AND a.MinStartDate = b.StartDate) x INNER JOIN (SELECT a.ProductId, a.MaxStartDate, b.Price AS MaxPrice FROM (SELECT ProductId, MAX(StartDate) AS MaxStartDate FROM Products GROUP BY ProductId) a INNER JOIN Products b ON a.ProductId = b.ProductId AND a.MaxStartDate = b.StartDate) y ON x.ProductId = y.ProductId
DISCLAIMER: This is from memory so I apologize if this is not entirely accurate. And it assumes that the StartDate is a datetime or is not repeated for each productId.
Hope this helps.

Related

How to find the maximum product id in customer wise category in sql?

Here I have the customer id and max order quantity, how can I get the productid column for maximum orderquantity along with the customerid and maxorderqty column.
Database: adventure works
Tables used:salesorerheader,salesorderdetails
SELECT customerid,
Max(totalqty)
FROM (SELECT customerid,
Sum(orderqty) AS Totalqty,
productid AS pdtid
FROM sales.salesorderheader a
INNER JOIN sales.salesorderdetail b
ON a.salesorderid = b.salesorderid
GROUP BY customerid,
productid)A
WHERE customerid = 29825
GROUP BY customerid
If you're interested in finding single record, you can use something like this:
SELECT TOP(1) CustomerID, max(totalqty) AS maxqty, pdtid
FROM
(
SELECT customerid, Sum(orderqty) AS Totalqty, productid AS pdtid
FROM sales.salesorderheader a
INNER JOIN sales.salesorderdetail b
ON a.salesorderid = b.salesorderid
GROUP BY customerid, productid
) A
WHERE CustomerID=29825
GROUP BY CustomerID, pdtid
ORDER BY max(totalqty) DESC
But... if you want to find several records with the same rank, use this:
SELECT *
FROM
(
SELECT RANK() OVER(ORDER BY max(totalqty) DESC) rnk, CustomerID, max(totalqty) AS maxqty, pdtid
FROM
(
SELECT customerid, Sum(orderqty) AS Totalqty, productid AS pdtid
FROM sales.salesorderheader a
INNER JOIN sales.salesorderdetail b
ON a.salesorderid = b.salesorderid
GROUP BY customerid, productid
) A
WHERE CustomerID=29825
GROUP BY CustomerID, pdtid
) B
WHERE rnk = 1
db<>fiddle
Another way is to 'join' sailes details again ;)

Get top one record of difference date

I try to get just one record of last Order of everysingle customer. ATM I have this idea but it giving me all of them Date of orders.
I work on dataBase AdventurerWorks2012
SELECT
H.CustomerID AS Customer,
H.SalesOrderID AS OrderNumber,
MAX(CAST(H.OrderDate AS DATE)) AS DateOrder
FROM
Sales.SalesOrderHeader H
JOIN
Sales.SalesOrderDetail D
ON H.SalesOrderID = D.SalesOrderID
GROUP BY
H.CustomerID,
H.SalesOrderID
ORDER BY
CustomerID;
You can use TOP 1 WITH TIES
select top 1 with ties
*
From
Sales.SalesOrderHeader H
INNER JOIN Sales.SalesOrderDetail D
ON H.SalesOrderID = D.SalesOrderID
ORDER BY row_number() over (partition by H.CustomerID order by H.OrderDate desc)
This applies and ordering with row_number() giving each customer's order an ID starting at 1 and going to N based off the OrderDate. The WITH TIES allows us to return the TOP 1 for each customer.
Another way, is using a CTE
;with cte as(
select top 1 with ties
*, RN = row_number() over (partition by H.CustomerID order by H.OrderDate desc)
From
Sales.SalesOrderHeader H
INNER JOIN Sales.SalesOrderDetail D
ON H.SalesOrderID = D.SalesOrderID)
select *
from cte
where RN = 1
I think you don't need to do JOIN:
SELECT h.*
FROM Sales.SalesOrderHeader h
WHERE OrderDate = (SELECT MAX(h1.OrderDate)
FROM Sales.SalesOrderHeader h1
WHERE h.CustomerID = h1.CustomerID
);
By this you will get customers with most recent order information.
select top 1 with ties
H.CustomerID AS Customer,
H.SalesOrderID as OrderNumber,
H.OrderDate As DataLast
From
Sales.SalesOrderHeader H
INNER JOIN Sales.SalesOrderDetail D
ON H.SalesOrderID = D.SalesOrderID
ORDER BY row_number() over (partition by H.CustomerID order by H.OrderDate desc)
This work like i need. Thanks!

Find product id of the top selling product of each day, using total sold quantity to determine the top selling product

Adventureworks2008R2 database.
The result I want is each day the MaxQantity sold, for example, OrderDate 2007-09-01 shall have the max quantity of 96 only, but my query gives me 3 different results from the same day, maybe because it is considering the timestamp as well
SELECT DISTINCT CAST(oh.OrderDate AS DATE) OrderDate, (od.ProductID),SUM(od.OrderQty) MAXOrderQty
FROM Sales.SalesOrderDetail od
Inner Join Sales.SalesOrderHeader oh
ON od.SalesOrderID = oh.SalesOrderID
GROUP BY od.ProductID, CAST(oh.OrderDate AS DATE), od.OrderQty
ORDER BY SUM(od.OrderQty) DESC
You can write CTE and self JOIN on MAX Qty by date
;WITH CTE(OrderDate,ProductID,MAXOrderQty) AS(
SELECT CAST(oh.OrderDate AS DATE) OrderDate,od.ProductID,SUM(od.OrderQty) MAXOrderQty
FROM Sales.SalesOrderDetail od
Inner Join Sales.SalesOrderHeader oh
ON od.SalesOrderID = oh.SalesOrderID
GROUP BY od.ProductID, CAST(oh.OrderDate AS DATE)
)
SELECT t1.*
FROM CTE t1 INNER JOIN (
select OrderDate,MAX(MAXOrderQty) 'MAXOrderQty'
from CTE
GROUP BY OrderDate
)t2 on t1.OrderDate = t2.OrderDate and t1.MAXOrderQty = t2.MAXOrderQty
It's much easier addressing problems like this with window functions. In this case, rank should do the trick:
SELECT OrderDate, ProductID, MaxOrderQty
FROM (SELECT OrderDate, ProductID, MaxOrderQty,
RANK() OVER (PARTITION BY OrderDate ORDER BY MaxOrderQty DESC) AS rk
FROM Sales.SalesOrderDetail) s
WHERE rk = 1

Using SQL how can I write a query to find the top 5 per category per month?

I am trying to get the Top 5 rows with the highest number for each category for a specific time interval such as a month. What I currently have returns 5 of the exact same descriptions for a category. I am trying to get the top five. This only happens when I try to sort it based on a time period.
WITH CustomerRank
AS
(SELECT
Count(*) AS "Count",
d.Item,
d.Description,
Name,
i.Type,
d.CreatedOn
FROM [dbo].i,
d,
dbo.b,
as,
a,
c
WHERE d.Inspection_Id = i.Id AND d.Inspection_Id = i.Id AND
b.Id = i.BuildingPart_Id AND b.as= Assessments.Id
AND as.Application_Id = a.Id AND a.Customer_Id = Customers.Id
group by d.Item, d.Description, Name, i.Type, d.CreatedOn
)
select * from (
SELECT "Count",Item,Description,Type,ROW_NUMBER() Over (PARTITION BY Name order by "Count" desc) AS RowNum, Name, CreatedOn
FROM CustomerRank
where CreatedOn > '2017-1-1 00:00:00'
) s where RowNum <6
Cheers
Try something like this:
WITH CustomerRank
AS
(SELECT
Count(*) AS "Count",
d.Item, d.Description, Name, i.Type
FROM dbo.Inspection i
INNER JOIN dbo.Details d ON d.Inspection_Id = i.Id
INNER JOIN dbo.BuildingParts b ON b.Id = i.BuildingPart_Id
INNER JOIN dbo.Assessments a ON a.Id = b.AssessmentId
INNER JOIN dbo.Applications ap ON ap.Id = a.Application_Id
INNER JOIN dbo.Customers c ON c.Id = a.Customer_Id
where CreatedOn > '2017-1-1 00:00:00'
group by d.Item, d.Description, Name, i.Type
)
select * from (
SELECT "Count",Item,Description,Type,ROW_NUMBER() Over (PARTITION BY Name order by "Count" desc) AS RowNum, Name
FROM CustomerRank
) s where RowNum <6
The idea is that the CreatedOn column must be removed from the GROUP BY clause (because if you keep it there, we would get a different row for each value of the CreatedOn column).
Also, it's better to use JOIN-s and aliases for each table.

Select maximum value of one table depending on 2 other tables

I have 3 tables
Orders (orderID, CustomerID)
Orderlines (orderID, ProdID)
Products (ProdID, CategoryID)!
I want to find the customerID which has the most different "CategoryID" in one order!
To get you there, start with the basic query to get your info:
SELECT o.customer_id
,l.orderid
,COUNT(DISTINCT categoryid) category_cnt
FROM orders o
JOIN orderlines l on l.orderid = o.orderid
JOIN products p ON l.prodid = p.prodid
GROUP BY l.customner_id, l.orderid
order by COUNT(DISTINCT categoryid) desc;
Once you see that this works out, we will add an analytic to this to show you the rank() function
SELECT o.customer_id
,l.orderid
,COUNT(DISTINCT categoryid) category_cnt
, rank() over (order by COUNT(DISTINCT categoryid) desc) as count_rank
FROM orders o
JOIN orderlines l on l.orderid = o.orderid
JOIN products p ON l.prodid = p.prodid
GROUP BY l.customner_id, l.orderid
order by COUNT(DISTINCT categoryid) desc;
Following so far? OK, so now we just need to push this down into a sub-query to get the record(s) ranked #1 (in case more than one customer order matches the top count)
SELECT customer_id, order_id, category_cnt
FROM (
SELECT o.customer_id
,l.orderid
,COUNT(DISTINCT categoryid) category_cnt
, rank() over (order by COUNT(DISTINCT categoryid) desc) as count_rank
FROM orders o
JOIN orderlines l on l.orderid = o.orderid
JOIN products p ON l.prodid = p.prodid
GROUP BY l.customner_id, l.orderid)
WHERE count_rank = 1;
Try;
with data_a as ( --distinct CategoryID cnt
select
o.orderID,
o.customerID,
count(DISTINCT p.CategoryID) cnt
from Orders o
join Orderlines ol.orderID = o.orderID
join Products p on p.ProdID = ol.ProdID
group by o.orderID, o.customerID
),
data as ( --get all count rnk
select
orderID,
customerID,
rank() over (partition by orderID, customerID order by cnt desc) rnk
from data_a
)
select
orderID,
customerID
from data
where rnk = 1
Step by step: Count distinct categories per order first. Then rank your orders, so that the orders with the most categories get rank #1. Then find customers for all orders ranked #1.
select distinct cutomerid
from orders
where orderid in
(
select orderid
from
(
select orderid, rank() over (order by category_count desc) as rnk
from
(
select ol.orderid, count(distinct p.distinctcategroyid) as category_count
from orderlines ol
join products p on p.prodid = ol.prodid
group by ol.orderid
) counted
) ranked
where rnk = 1
);
Something like that i guess
SELECT o.customerID, t.category_cnt
FROM (SELECT l.orderid, COUNT(DISTINCT categoryid) category_cnt
FROM orderlines l
JOIN products p ON l.prodid = p.prodid
GROUP BY l.orderid
ORDER BY category_cnt DESC) t
JOIN orders o ON o.orderid = t.orderid
WHERE rownum < 2