SQL: How to get Max Order number row from multiple rows - sql

How can I Select Max Order_number row from given multiple rows? per example below results 9010305604 is the max number. I need to select 9010305604row
SELECT DISTINCT
CUST.PRIMARY_EMAIL_ADDRESS [EMAIL],
OD.ORDER_NO [ORDER_NUMBER],
CUST.MASTER_CUSTOMER_ID [CUSTOMER ID],
CUST.SUB_CUSTOMER_ID,
CUST.USR_ORIG_JOIN_DATE,
OD.CYCLE_END_DATE
, OD.RATE_CODE
,OD.CYCLE_BEGIN_DATE
--, OD.ORIGINAL_ORDER_NO
FROM CUSTOMER CUST (NOLOCK)
INNER JOIN ORDER_DETAIL OD (NOLOCK)
ON CUST.MASTER_CUSTOMER_ID = OD.SHIP_MASTER_CUSTOMER_ID
AND OD.SHIP_SUB_CUSTOMER_ID = CUST.SUB_CUSTOMER_ID
INNER JOIN ORDER_MASTER OM (NOLOCK)
ON OD.ORDER_NO = OM.ORDER_NO
INNER JOIN PRODUCT PROD
ON [PROD].[PRODUCT_ID] = [OD].[PRODUCT_ID]
WHERE OD.SUBSYSTEM = 'MBR'
AND OD.PRODUCT_CODE IN ('PROFESSIONAL')
AND OD.LINE_STATUS_CODE = 'A'
-- AND OD.CYCLE_BEGIN_DATE <= GETDATE()
AND OD.CYCLE_END_DATE >= GETDATE()
--AND OD.ORIGINAL_ORDER_NO IS NULL
AND CUST.PRIMARY_EMAIL_ADDRESS IS NOT NULL
AND CUST.USR_ORIG_JOIN_DATE >cast(DATEADD(day, -120,GETDATE()) AS DATE)
AND OM.USR_BULK_ORDER_NO IS NULL
AND MASTER_CUSTOMER_ID = '4655302'
EMAIL ORDER_NUMBER CUSTOMER ID SUB_CUSTOMER_ID USR_ORIG_JOIN_DATE CYCLE_END_DATE RATE_CODE CYCLE_BEGIN_DATE
sannyastari#gmail.com 9010305603 4655302 0 2020-11-21 00:00:00.000 2020-12-31 00:00:00.000 1YR 2020-11-21 00:00:00.000
sannyastari#gmail.com 9010305604 4655302 0 2020-11-21 00:00:00.000 2021-12-31 00:00:00.000 1YR 2021-01-01 00:00:00.000

Use a TOP query?
SELECT DISTINCT TOP 1
CUST.PRIMARY_EMAIL_ADDRESS [EMAIL],
OD.ORDER_NO [ORDER_NUMBER],
...
(rest of your query)
ORDER BY
OD.ORDER_NO DESC;

Related

SQL left join same column and table

I have a customer order data and would like to do analysis on customer retention after price changes.
The order table is as follows:
customer_id order_number order_delivered_date
14156 R980193622 2/6/2020 14:51
1926396 R130222714 22/5/2020 11:02
1085123 R313065343 22/5/2020 14:50
699858 R693959049 8/6/2020 17:03
1609769 R195969327 3/6/2020 16:14
14156 R997103187 27/6/2020 14:01
1926396 R403942827 11/6/2020 14:42
1926396 R895013611 8/7/2020 17:04
So, I would like to pull order in the period before new price. Assume the new price implementation is on 10/6/2020. I would like to do left join to order after the new price on the customer_id.
Before is a set of data dated 10/5/2020 00:00:00 to 9/6/2020 23:59:59 while After is a set of data dated 10/6/2020 00:00:00 to 9/7/2020 23:59:59.
The desired table:
Before After
14156 14156
1926396 1926396
1085123 Null
699858 Null
1609769 Null
If customer_id is found side by side it means they are retained. It should be simple...But I have been stucked.
EDIT:
This is few code that I have been trying
First try:
select ol2.customer_id as before, ol.customer_id as after
from master.order_level ol,
left join master.order_level ol2
on ol2.customer_id = ol.customer_id
where order_delivered_date between '2020-05-10 00:00:00' and '2020-07-09 23:59:59' and country_id = 2
Second try:
SELECT ol.customer_id as before, ol2.customer_id as after
FROM master.order_level ol,master.order_level ol2
left join master.order_level
ON ol.customer_id = ol2.customer_id
WHERE ol.order_delivered_date between '2020-05-10 00:00:00' and '2020-06-09 23:59:59' and ol.country_id =2 and ol2.order_delivered_date between '2020-06-10 00:00:00' and '2020-07-09 23:59:59' and ol2.country_id =2
No need to do a join, you can just use you can do a simple group by and use case and aggregate functions. I also made a fiddle showing it in action here
SELECT customer_id,
CASE
WHEN MIN(order_delivered_date) < '3-15-2019' THEN customer_id
ELSE NULL END customer_before,
CASE
WHEN MAX(order_delivered_date) >= '3-15-2019' THEN customer_id
ELSE NULL END customer_after
FROM my_table
GROUP BY customer_id
there qyery will giva you results like this
customer_id customer_before customer_after
4 4 (null)
1 1 1
3 3 (null)
2 2 2
with before (customer_id) as
( select distinct customer_id from orders where order_delivered_date <= '10/06/2020'
),
after (customer_id) as
(select distinct customer_id from orders where order_delivered_date between '10/06/2020' and '09/07/2020')
select
before.customer_id,
after.customer_id
from before left outer join after on before.customer_id = after.customer_id
you can use union
select customer_id as before, null as after
from #order
where order_delivered_date <'2020-06-10'
union
select null as before, customer_id as after
from #order
where order_delivered_date >='2020-06-10'
results

How can I get distinct data from one col

I need to get member personal data for all our members whose subscriptions have lapsed i.e. have a subscription end date before 31/03/2020, however I want to show one member record only (distinct by membership number) ideally the most recent one
I've tried a ROW_NUMBER() solution SQL - Distinct One Col, Select Multiple other? and a cross apply solution sql distinct, getting 2 columns but I can't get it to work.
SELECT membershipnumber AS Id,
subscription.enddate
FROM [dbo].[userprofile]
INNER JOIN dbo.subscription
ON userprofile.id = subscription.userprofileid
INNER JOIN dbo.subscriptiontype
ON subscriptiontype.id = subscription.subscriptiontypeid
Output is
Id Enddate
1 2006-04-01 00:00:00.000
1 2001-04-01 00:00:00.000
1 1999-04-01 00:00:00.000
1 1998-04-01 00:00:00.000
1 2008-04-01 00:00:00.000
1 2007-04-01 00:00:00.000
1 2011-04-01 00:00:00.000
1 2005-04-01 00:00:00.000
1 2000-04-01 00:00:00.000
1 1997-04-01 00:00:00.000
2 1999-04-01 00:00:00.000
2 2012-04-01 00:00:00.000
2 2004-04-01 00:00:00.000
2 2001-04-01 00:00:00.000
2 2018-04-01 00:00:00.000
2 2009-04-01 00:00:00.000
2 2005-04-01 00:00:00.000
2 1997-04-01 00:00:00.000
Desired output
Id Enddate
1 2011-04-01 00:00:00.000
2 2018-04-01 00:00:00.000
Solved sql answer
;WITH cte
AS (SELECT membershipnumber AS Id,
subscription.enddate,
Row_number()
OVER (
partition BY membershipnumber
ORDER BY subscription.enddate DESC) AS rownumber
FROM [dbo].[userprofile]
INNER JOIN dbo.subscription
ON userprofile.id = subscription.userprofileid
INNER JOIN dbo.subscriptiontype
ON subscriptiontype.id = subscription.subscriptiontypeid
)
SELECT *
FROM cte
WHERE rownumber = 1
https://stackoverflow.com/a/6841644/5859743
Not sure if I got your question right.
but you can use DISTINCT in the SELECT, that would show only one record for each member.
SELECT DISTINCT Membershipnumber as Id
,'P' as PartyType
,'A' as Status
,case
when Name = 'Standard Membership paid annually.' and EndDate > '2020-03-31' then 'Member'
when Name = 'Lapsed subscription renewal' and EndDate > '2020-03-31' then 'Member'
when Name = '3 Year Subscription (members outside of UK and Ireland, Jersey, Guernsey and the Channel Islands)' and EndDate > '2020-03-31' then 'Overseas member'
when Name = '1 Year Subscription (members outside of UK and Ireland, Jersey, Guernsey and the Channel Islands).' and EndDate > '2020-03-31' then 'Overseas member'
when Name = 'Lapsed subscription renewal' and EndDate > '2020-03-31' then 'Member'
when Name = 'Lifetime membership' then 'Lifetime member'
when Name = 'Retired membership paid annually' and EndDate > '2020-03-31' then 'Retired member'
else 'Non member'
end As MemberType
,Title as NamePrefix
,FirstName as FirstName
,Surname as LastName
,DateOfBirth as BirthDate
,'Home' as AddressPurpose
,'Default' as CommunicationReasons
,AddressLine1
,AddressLine2
,AddressLine3
,Addressline4 as CityName
,'' as CountrySubEntityName
,Country as CountryCode
,'' as CountryName
,Postcode as PostalCode
,EmailAddress as Email
FROM [dbo].[UserProfile]
inner join dbo.Subscription on
UserProfile.Id = Subscription.UserProfileId
inner join dbo.SubscriptionType on
SubscriptionType.id = Subscription.SubscriptionTypeId```
If you are getting as above mentioned output. Then from that, your desired output will easily get using distinct.
; with cte as (
----- query which gives you above mentioned output
)
select distinct id, max(Enddate) as Enddate from cte
I suspect you want something like this:
select *
from (select . . ., -- all the columns you want
row_number() over (partition by Membershipnumber as Id order by s.Enddate) as seqnum
from [dbo].[UserProfile] up inner join
dbo.Subscription s
on up.Id = s.UserProfileId inner join
dbo.SubscriptionType st
on st.id = s.SubscriptionTypeId
) x
where seqnum = 1;

Get count of orders that is closed in less than 30 minutes

The below query returns the following output
Output
OutletID Avg Receive Avg Ready Avg Dispatch Avg Close Customers Orders
32 58 29 0 200 6 6
23 27 1 0 3 7 3
The Query
SELECT
Outlets.OutletID,
AVG(DATEDIFF(mi, Orders.OrderDate, ReceivedOrders.ReceivingDate)) AS [Avg Receive],
AVG(DATEDIFF(mi, ReceivedOrders.ReceivingDate, ReadyOrders.ReadyDate)) AS [Avg Ready],
AVG(DATEDIFF(mi, ReadyOrders.ReadyDate, DispatchedOrders.DispatchedDate)) AS [Avg Dispatch],
AVG(DATEDIFF(mi, DispatchedOrders.DispatchedDate, ClosedOrders.ClosingDate)) AS [Avg Close],
Count (dbo.Orders.CustomerID) as Customers,
Count (dbo.Orders.OrderID) as Orders
FROM dbo.Orders
INNER JOIN dbo.Outlets
ON dbo.Orders.OutletID = dbo.Outlets.OutletID
INNER JOIN dbo.Brands
ON dbo.Brands.BrandID = dbo.Outlets.BrandID
INNER JOIN dbo.ReceivedOrders
ON dbo.Orders.OrderID = dbo.ReceivedOrders.OrderID
LEFT JOIN dbo.ReadyOrders
ON dbo.Orders.OrderID = dbo.ReadyOrders.OrderID
LEFT JOIN dbo.DispatchedOrders
ON dbo.Orders.OrderID = dbo.DispatchedOrders.OrderID
LEFT JOIN dbo.ClosedOrders
ON dbo.Orders.OrderID = dbo.ClosedOrders.OrderID
WHERE Orders.OrderDate BETWEEN '01/Dec/2017 10:00 AM' AND '05/Dec/2017 12:00 am'
and dbo.Orders.OrderID not in (select OrderID from [dbo].[CanceledOrders])
GROUP BY Outlets.OutletID,
Brands.BrandName,
dbo.Outlets.OutletName
ORDER BY dbo.Outlets.OutletName, Brands.BrandName
what i am looking for is to get count of orders that is closed under 30 minutes for each outlet so the output should be like below.
Desired Output
OutletID Avg Receive Avg Ready Avg Dispatch Avg Close Customers Orders lessthan30
32 58 29 0 200 6 6 4
23 27 1 0 3 7 3 2
The query to get the difference between closing time and order time
SELECT
COUNT(Orders.OrderID) AS [less30]
FROM [dbo].[Orders]
INNER JOIN dbo.ClosedOrders
ON dbo.ClosedOrders.[OrderID] = Orders.OrderID
WHERE [OrderStatus] = 'Closed'
AND DATEDIFF(mi, Orders.OrderDate, ClosedOrders.ClosingDate) < 30
AND Orders.OrderDate BETWEEN '01/Dec/2017 10:00 AM' AND '05/Dec/2017 12:00 am'
So how can i combine the tow queries into one query
I dont have the exact schema but I think this should work
SELECT
Outlets.OutletID,
AVG(DATEDIFF(mi, Orders.OrderDate, ReceivedOrders.ReceivingDate)) AS [Avg Receive],
AVG(DATEDIFF(mi, ReceivedOrders.ReceivingDate, ReadyOrders.ReadyDate)) AS [Avg Ready],
AVG(DATEDIFF(mi, ReadyOrders.ReadyDate, DispatchedOrders.DispatchedDate)) AS [Avg Dispatch],
AVG(DATEDIFF(mi, DispatchedOrders.DispatchedDate, ClosedOrders.ClosingDate)) AS [Avg Close],
Count (dbo.Orders.CustomerID) as Customers,
Count (dbo.Orders.OrderID) as Orders,
count less30 as Closedin30
FROM dbo.Orders
INNER JOIN dbo.Outlets
ON dbo.Orders.OutletID = dbo.Outlets.OutletID
INNER JOIN dbo.Brands
ON dbo.Brands.BrandID = dbo.Outlets.BrandID
INNER JOIN dbo.ReceivedOrders
ON dbo.Orders.OrderID = dbo.ReceivedOrders.OrderID
LEFT JOIN dbo.ReadyOrders
ON dbo.Orders.OrderID = dbo.ReadyOrders.OrderID
LEFT JOIN dbo.DispatchedOrders
ON dbo.Orders.OrderID = dbo.DispatchedOrders.OrderID
LEFT JOIN dbo.ClosedOrders
ON dbo.Orders.OrderID = dbo.ClosedOrders.OrderID
left join
(
SELECT
Orders.OrderID as less30
FROM [dbo].[Orders]
INNER JOIN dbo.ClosedOrders
ON dbo.ClosedOrders.[OrderID] = Orders.OrderID
WHERE [OrderStatus] = 'Closed'
AND DATEDIFF(mi, Orders.OrderDate, ClosedOrders.ClosingDate) < 30
AND Orders.OrderDate BETWEEN '01/Dec/2017 10:00 AM' AND '05/Dec/2017 12:00 am'
) closedIntime
on
(
dbo.Orders.OrderID = closedIntime.less30
)
WHERE Orders.OrderDate BETWEEN '01/Dec/2017 10:00 AM' AND '05/Dec/2017 12:00 am'
and dbo.Orders.OrderID not in (select OrderID from [dbo].[CanceledOrders])
GROUP BY Outlets.OutletID,
Brands.BrandName,
dbo.Outlets.OutletName
ORDER BY dbo.Outlets.OutletName, Brands.BrandName

How to join tally dates with list of periods to retrieve wanted results?

I have a list of tally dates that I want to combine with prices, but I want for results to have all the dates from tally and dates and price values from prices (and null prices when no periods correspond to tally date)
Dates
Date
2017-12-22
2017-12-23
2017-12-24
2017-12-25
2017-12-26
2017-12-27
2017-12-28
2017-12-29
2017-12-30
2017-12-31
Prices
periodstart periodend price productID
2017-12-23 2017-12-25 50 1
2017-12-26 2017-12-29 10 1
Sql query result
date price productid
2017-12-22 null 1
2017-12-23 50 1
2017-12-24 50 1
2017-12-25 50 1
2017-12-26 10 1
2017-12-27 10 1
2017-12-28 10 1
2017-12-29 10 1
2017-12-30 null 1
2017-12-31 null 1
UPDATE
I added productID column in prices
rextester: http://rextester.com/ADJZSW20744
create table dbo.calendar (
[date] date primary key clustered
);
insert into dbo.calendar values
('2017-12-22'),('2017-12-23'),('2017-12-24')
,('2017-12-25'),('2017-12-26'),('2017-12-27')
,('2017-12-28'),('2017-12-29'),('2017-12-30')
,('2017-12-31');
create table prices (
periodstart date
, periodend date
, price int
, productid int
);
insert into prices values
('2017-12-23','2017-12-25',50,1)
,('2017-12-26','2017-12-29',10,1)
,('2017-12-22','2017-12-23',50,2)
,('2017-12-26','2017-12-27',10,2);
query: This will work with multiple products:
select
c.Date
, p.Price
, x.ProductId
from dbo.Calendar c
outer apply (
select distinct
ProductId
from prices
) x
left join dbo.Prices p on
c.Date >= p.PeriodStart
and c.Date <= p.PeriodEnd
and x.ProductId = p.ProductId
order by x.ProductId, c.Date;
A simple left join should do the trick
Select A.Date
,B.Price
From Dates A
Left Join Prices B on A.Date Between B.periodstart and B.periodend
Try this:
SELECT Date
, price
FROM Dates d
LEFT JOIN Prices p
ON d.Date BETWEEN p.periodstart AND ISNULL(p.periodend, d.Date)
To avoid conflicts in case your periods are intersecting or don't have an ending date, take the latest start period using an apply:
SELECT Date
, price
FROM Dates d
OUTER APPLY
(
SELECT TOP 1 price
FROM Prices p
WHERE d.Date BETWEEN p.periodstart AND ISNULL(p.periodend, d.Date)
ORDER BY p.periodstart DESC
) oa

Get Last Change Date in SQL

StockCode TimeStamp UnitPrice TrnDate
---------------------------------------------------------------
360120 0x000000000DBE9EED 16.8000 2015-02-13 0:00:00.000
360120 0x000000000DBEE175 16.8000 2015-02-17 00:00:00.000
360120 0x000000000DC177AC 16.8000 2015-02-24 00:00:00.000
360120 0x000000000DC1EEFB 16.0000 2015-02-25 00:00:00.000
360120 0x000000000DC1E9BE 16.8000 2015-02-25 00:00:00.000
360120 0x000000000DC261CE 16.0000 2015-02-27 00:00:00.000
360120 0x000000000DC2628D 16.8000 2015-02-27 00:00:00.000 **
360120 0x000000000DFC46EA 16.8000 2015-03-02 00:00:00.000
The query needs to return 2015-02-27 where price went form 16.000 to 16.8000,
which is the last price change date for this item in the price history table.
The way I wrote it, the query it only works if the price didn't change back to a price that exists in the table for that stock code.
SELECT
MAX(MinTrnDate) as LastTrnDate
FROM
(SELECT
a.UnitPrice, MIN(TrnDate) as MinTrnDate
FROM
(SELECT
ph.StockCode,
CONVERT(DECIMAL(18,4), (ph.InvoiceValue/ ph.InvoiceQty)) as UnitPrice,
ph.TrnDate
FROM
ArSalesMove ph
JOIN
ArCustomer c WITH(NOLOCK) on ph.Customer = c.Customer
WHERE
LTRIM(RTRIM(ph.StockCode)) = '360120'
AND (ph.InvoiceValue/ ph.InvoiceQty) > 0
AND c.PriceCode = 'A') AS a
WHERE
a.UnitPrice > 0
GROUP BY a.UnitPrice) AS b
HAVING
MIN(CONVERT(DECIMAL(18, 2), UnitPrice)) <> MAX(CONVERT(DECIMAL(18, 2), UnitPrice)) --Used to exclude stockcodes with no change...
For SQL Server 2012 or newer:
;WITH
cte AS
(
SELECT *,
LAG(UnitPrice, 1) OVER (PARTITION BY StockCode ORDER BY TrnDate) AS LastPrice
FROM PriceHistory
)
SELECT StockCode, MAX(TrnDate)
FROM cte
WHERE UnitPrice != LastPrice
GROUP BY StockCode
For SQL Server 2005 and up:
;WITH
cte AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY StockCode ORDER BY TrnDate) AS RowNumber
FROM PriceHistory
)
SELECT c2.StockCode, MAX(c2.TrnDate)
FROM cte c1
INNER JOIN cte c2 ON c1.StockCode = c2.StockCode AND c1.RowNumber + 1 = c2.RowNumber
WHERE c1.UnitPrice != c2.UnitPrice
GROUP BY c2.StockCode