Bring next value after condition - sql

I am trying to fetch the next value after the condition is found. In this case, it is a row from 13/05/2021 the result I want to see is the row from 19/05/2021 Cte and CTE1 bring correct results.
I can't figure out what is wrong with my query.
<with cte as
(
select
customerid
,max(timestamp) as [Case Submitted]
,row_number() over (partition by [CustomerId] order by [CustomerId] ,max([timestamp]) desc) as rownum
from Table1
where substatus = 'Case Submitted'
and timestamp > '2021-01-01'
Group by
customerid
,timestamp
)
,CTE2 as
(
Select *
from cte
Where rownum = 1
),
CTE3 as
(
select
PS.customerid
,(PS.timestamp) as [Customer Support]
,row_number() over (partition by PS.customerid order by PS.customerid ) as rownum
from Table1 PS
left join CTE2 C2 on C2.customerid = PS.customerid and C2.[Case Submitted] > PS.timestamp and C2.rownum =1
where status = 'Customer Support'
and timestamp > '2021-01-01'
Group by
PS.customerid
,ps.timestamp
)
Select*
from CTE3>

untested notepad scribble
with CTE1 as
(
select
customerid
, [timestamp] as [Case Submitted]
, rownum = row_number() over (partition by CustomerId order by [timestamp] desc)
from Table1
where substatus = 'Case Submitted'
and [timestamp] > cast('2021-01-01' as date)
),
CTE2 AS
(
select
PS.customerid
, PS.timestamp as [Customer Support]
, rownum = row_number() over (partition by PS.customerid order by PS.timestamp)
from Table1 as PS
join CTE1 as C1
on C1.customerid = PS.customerid
and C1.[Case Submitted] > PS.[timestamp]
and C1.rownum = 1
where PS.status = 'Customer Support'
and [timestamp] > cast('2021-01-01' as date)
)
select *
from CTE2
where rownum = 1

Related

How to group data with conditions?

I'm trying to turn my current table using sql
customer.id sale_date
15 1/12/2017
15 2/12/2017
15 7/12/2017
12 6/09/2017
12 12/09/2017
16 8/14/2017
13 6/01/2017
13 7/01/2017
into something like this.
sale_date1 is the first order date.
sale_date2 is any order date one month after sale_date1.
sale_date3 is any order date five months after sale_date1.
customer.id sale_date1 sale_date2 sale_date3(at least 5 months after sale_date1)
15 1/12/2017 2/12/2017 7/12/2017
12 6/07/2017 NULL 12/09/2017
16 8/14/2017 NULL NULL
13 6/01/2017 7/01/2017 NULL
One option here would be to use correlated sub-queries to populate each of the three columns:
WITH cte AS (
SELECT [customer.id], MIN(sale_date) AS min_sale_date
FROM yourTable
GROUP BY [customer.id]
)
SELECT
[customer.id],
min_sale_date AS sale_date1,
(SELECT MIN(t2.sale_date) FROM yourTable t2
WHERE t1.[customer.id] = t2.[customer.id] AND
t2.sale_date >= DATEADD(month, 1, t1.min_sale_date) AND
t2.sale_date < DATEADD(month, 5, t1.min_sale_date)) AS sale_date2,
(SELECT MIN(t2.sale_date) FROM yourTable t2
WHERE t1.[customer.id] = t2.[customer.id] AND
t2.sale_date >= DATEADD(month, 5, t1.min_sale_date)) AS sale_date3
FROM cte t1
ORDER BY [customer.id];
Demo
Try below using row_number() and conditional aggregation
select customerid,max(case when seq=1 then sale_date end) as date1,
max(case when seq=2 then sale_date end) as date2,
max(case when seq=3 then sale_date end) as date3
from
(
select *, row_number() over(partition by customerid order by sale_date) as seq
from tablename
)X
group by customerid
I THINK THIS IS WHAT YOU WANT
SELECT A.customer.id, SALES1.sale_date , SALES2.sale_date ,SALES3.sale_date , SALES4.sale_date,SALES5.sale_date from
(SELECT distinct customer.id ,
From yourTable)A
LEFT JOIN
(SELECT * from
(SELECT customer.id, sale_date
ROW_NUMBER() OVER(ORDER BY sale_date ASC)
AS R1,
name, recovery_model_desc
FROM yourTable)S1 where R1=1)SALES1
A.customer.id = SALES1.customer.id
LEFT JOIN
(SELECT * from
(SELECT customer.id, sale_date
ROW_NUMBER() OVER(ORDER BY sale_date ASC)
AS R1,
name, recovery_model_desc
FROM yourTable)S1 where R1=2)SALES2
A.customer.id = SALES1.customer.id
LEFT JOIN
(SELECT * from
(SELECT customer.id, sale_date
ROW_NUMBER() OVER(ORDER BY sale_date ASC)
AS R1,
name, recovery_model_desc
FROM yourTable)S1 where R1=3)SALES3
A.customer.id = SALES1.customer.id
LEFT JOIN
(SELECT * from
(SELECT customer.id, sale_date
ROW_NUMBER() OVER(ORDER BY sale_date ASC)
AS R1,
name, recovery_model_desc
FROM yourTable)S1 where R1=2)SALES2
A.customer.id = SALES1.customer.id
LEFT JOIN
(SELECT * from
(SELECT customer.id, sale_date
ROW_NUMBER() OVER(ORDER BY sale_date ASC)
AS R1,
name, recovery_model_desc
FROM yourTable)S1 where R1=4)SALES4
A.customer.id = SALES1.customer.id
LEFT JOIN
(SELECT * from
(SELECT customer.id, sale_date
ROW_NUMBER() OVER(ORDER BY sale_date ASC)
AS R1,
name, recovery_model_desc
FROM yourTable)S1 where R1=2)SALES2
A.customer.id = SALES1.customer.id
LEFT JOIN
(SELECT * from
(SELECT customer.id, sale_date
ROW_NUMBER() OVER(ORDER BY sale_date ASC)
AS R1,
name, recovery_model_desc
FROM yourTable)S1 where R1=5)SALES5
A.customer.id = SALES1.customer.id
try this:
with mindate as (
select id, min(sale_date) MinDate,
DATEADD(month, 1, min(sale_date)) MinDatePlus1Month,
DATEADD(month, 5, min(sale_date)) MinDatePlus2Month
from yourtable
group by id
)
select f1.id, f1.MinDate sale_date1, f2.sale_date sale_date2, f3.sale_date sale_date3
from mindate f1
left outer join yourtable f2 on f1.id=f2.id and f1.MinDatePlus1Month=f2.sale_date
left outer join yourtable f3 on f1.id=f3.id and f1.MinDatePlus2Month=f3.sale_date

How to find the highest value in a year and in all months

I want to return a year in which was the most contracts made and a month throughout all years - in which month the highest number of contracts is made.
I've tried:
SELECT
cal.CalendarYear
,cal.MonthOfYear
,COUNT(*) AS Cnt
FROM dim.Application app
JOIN dim.Calendar cal ON app.ApplicationDateID = cal.DateId
--WHERE (CalendarYear IS NULL) OR (MonthOfYear IS NULL)
GROUP BY
cal.CalendarYear
,cal.MonthOfYear
WITH CUBE
ORDER BY COUNT(*) DESC
and...
--;WITH maxYear AS (
SELECT TOP 1
cal.CalendarYear AS [Year]
,0 AS [Month]
,COUNT(*) AS Cnt
FROM dim.Application app
JOIN dim.Calendar cal ON app.ApplicationDateID = cal.DateId
GROUP BY cal.CalendarYear
-- ORDER BY COUNT(*) DESC
--)
UNION ALL
--,maxMonth AS (
SELECT TOP 1
0 AS [Year]
,cal.MonthOfYear AS [Month]
,COUNT(*) AS Cnt
FROM dim.Application app
JOIN dim.Calendar cal ON app.ApplicationDateID = cal.DateID
GROUP BY cal.MonthOfYear
ORDER BY COUNT(*) DESC
--)
Any help would be appreciated. Thanks.
This will ORDER BY each portion of the UNION independently, and still have the results joined in one SELECT...
SELECT x.* FROM (
SELECT TOP 1
cal.CalendarYear AS [Year]
,0 AS [Month]
,COUNT(*) AS Cnt
FROM dim.Application app
JOIN dim.Calendar cal ON app.ApplicationDateID = cal.DateId
GROUP BY cal.CalendarYear
ORDER BY COUNT(*) DESC
) x
UNION ALL
SELECT x.* FROM (
SELECT TOP 1
0 AS [Year]
,cal.MonthOfYear AS [Month]
,COUNT(*) AS Cnt
FROM dim.Application app
JOIN dim.Calendar cal ON app.ApplicationDateID = cal.DateID
GROUP BY cal.MonthOfYear
ORDER BY COUNT(*) DESC
) x
Get the counts per year and month and use row_number to get the year and month with the highest contracts.
SELECT
MAX(CASE WHEN year_rank=1 then Year END) as Highest_contracts_year,
MAX(CASE WHEN year_rank=1 then Year_count END) as Year_Contracts_count
MAX(CASE WHEN month_year_rank=1 then Month END) as Highest_contracts_Month,
MAX(CASE WHEN month_year_rank=1 then Month_Year_count END) as MonthYear_Contracts_count
FROM (SELECT T.*
,ROW_NUMBER() OVER(ORDER BY Year_Cnt DESC) as Year_rank
,ROW_NUMBER() OVER(ORDER BY Month_Year_Cnt DESC) as Month_Year_rank
FROM (SELECT
cal.CalendarYear AS [Year]
,cal.MonthOfYear AS [Month]
,COUNT(*) OVER(PARTITION BY cal.CalendarYear) AS Year_Cnt
,COUNT(*) OVER(PARTITION BY cal.MonthOfYear) AS Month_Year_Cnt
FROM dim.Application app
JOIN dim.Calendar cal ON app.ApplicationDateID = cal.DateId
) T
) T
You should specify what needs to be done when there are ties for highest counts. Assuming you need all highest count rows when there are ties, use
With ranks as
(SELECT T.*
,RANK() OVER(ORDER BY Year_Cnt DESC) as Year_rank
,RANK() OVER(ORDER BY Month_Year_Cnt DESC) as Month_Year_rank
FROM (SELECT
cal.CalendarYear AS [Year]
,cal.MonthOfYear AS [Month]
,COUNT(*) OVER(PARTITION BY cal.CalendarYear) AS Year_Cnt
,COUNT(*) OVER(PARTITION BY cal.MonthOfYear) AS Month_Year_Cnt
FROM dim.Application app
JOIN dim.Calendar cal ON app.ApplicationDateID = cal.DateId
) T
)
SELECT *
FROM (SELECT DISTINCT Year,Year_Cnt FROM RANKS WHERE Year_rank=1) ry
CROSS JOIN (SELECT DISTINCT Month,Month_Year_Cnt FROM RANKS WHERE Month_Year_rank=1) rm
EDIT: This might be what you want, unless you want it on single line:
select calendaryear AS 'year/month', cnt from (
SELECT TOP 1
cal.CalendarYear
,COUNT(*) AS Cnt
FROM dim.Application AS app
JOIN dim.Calendar AS cal ON app.ApplicationDateID = cal.DateId
GROUP BY
cal.CalendarYear
ORDER BY COUNT(*) DESC
) as year
UNION ALL
select MonthOfYear, Cnt FROM (
SELECT TOP 1
cal.CalendarYear
,cal.MonthOfYear
,COUNT(*) AS Cnt
FROM dim.Application AS app
JOIN dim.Calendar AS cal ON app.ApplicationDateID = cal.DateId
GROUP BY
cal.CalendarYear
,cal.MonthOfYear
ORDER BY COUNT(*) DESC
) AS month
It returns following result where month 3 is in fact 2016:
year/month cnt
2017 4
3 2
I have used following data as input
create table #calendar (DateId int, calendaryear int, monthofyear int)
create table #application (applicationdateId int)
insert into #calendar values (1,2017,01)
insert into #calendar values (2,2017,02)
insert into #calendar values (3,2017,03)
insert into #calendar values (4,2016,01)
insert into #calendar values (5,2016,03)
insert into #application values (1)
insert into #application values (1)
insert into #application values (2)
insert into #application values (3)
insert into #application values (4)
insert into #application values (5)
insert into #application values (5)

SQL Server 2008 calculating data difference when we have only one date column

I have a date column Order_date and I am looking for ways to calculate the date difference between customer last order date and his recent previous ( previous form last) order_date ....
Example
Customer : 1, 2 , 1 , 1
Order_date: 01/02/2007, 02/01/2015, 06/02/2014, 04/02/2015
As you can see customer # 1 has three orders.
I want to know the date difference between his recent order date (04/02/2015) and his recent previous (06/02/2014).
For SQL Server 2012 & 2014 you could use LAG with a DATEDIFF to see the number of days between them.
For older versions, a CTE would probably be your best bet:
;WITH CTE AS
(
SELECT CustomerID,
Order_Date,
rn = ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY Order_Date DESC)
)
SELECT c1.CustomerID,
DATEDIFF(d, c1.Order_Date, c2.Order_Date)
FROM CTE c1
INNER JOIN CTE c2 ON c2.rn = c1.rn + 1
In SQL Server 2012+, you can use lag() to get the difference between any two dates:
select t.*,
datediff(day, lag(order_date) over (partition by customer order by order_date),
order_date) as days_dff
from table t;
If you have an older version, you can do something similar with correlated subqueries or outer apply.
EDIT:
If you just want the difference between the two most recent dates, use conditional aggregation instead:
select customer,
datediff(day, max(case when seqnum = 2 then order_date end),
max(case when seqnum = 1 then order_date end)
) as MostRecentDiff
from (select t.*,
row_number() over (partition by customer order by order_date desc) as seqnum
from table t
) t
group by customer;
If you're using SQL Server 2008 or later, you can try CROSS APPLY.
SELECT [customers].[customer_id], DATEDIFF(DAY, MIN([recent_orders].[order_date]), MAX([recent_orders].[order_date])) AS [elapsed]
FROM [customers]
CROSS APPLY (
SELECT TOP 2 [order_date]
FROM [orders]
WHERE ([orders].[customer_id] = [customers].[customer_id])
) [recent_orders]
GROUP BY [customers].[customer_id]
SELECT DATEDIFF(DAY, Y.PrevLastOrderDate, Y.LastOrderDate) AS PreviousDays
FROM
(
SELECT X.LastOrderDate
, (SELECT MAX(OrderDate) FROM dbo.Orders SO WHERE SO.CustomerID=1 AND SO.OrderDate < X.LastOrderDate) AS PrevLastOrderDate
FROM
(
select MAX(OrderDate) AS LastOrderDate
FROM dbo.Orders O
WHERE O.CustomerID=1
)X
)Y
drop table #Invoices
create table #Invoices ( OrderId int , OrderDate datetime )
insert into #Invoices (OrderId , OrderDate )
select 101, '01/01/2001' UNION ALL Select 202, '02/02/2002' UNION ALL Select 303, '03/03/2003'
UNION ALL Select 808, '08/08/2008' UNION ALL Select 909, '09/09/2009'
;
WITH
MyCTE /* http://technet.microsoft.com/en-us/library/ms175972.aspx */
( OrderId,OrderDate,ROWID) AS
(
SELECT
OrderId,OrderDate
, ROW_NUMBER() OVER ( ORDER BY OrderDate ) as ROWID
FROM
#Invoices inv
)
SELECT
OrderId,OrderDate
,(Select Max(OrderDate) from MyCTE innerAlias where innerAlias.ROWID = (outerAlias.ROWID-1) ) as PreviousOrderDate
,
[MyDiff] =
CASE
WHEN (Select Max(OrderDate) from MyCTE innerAlias where innerAlias.ROWID = (outerAlias.ROWID-1) ) iS NULL then 0
ELSE DATEDIFF (mm, OrderDate , (Select Max(OrderDate) from MyCTE innerAlias where innerAlias.ROWID = (outerAlias.ROWID-1) ) )
END
, ROWIDMINUSONE = (ROWID-1)
, ROWID as ROWID_SHOWN_FOR_KICKS , OrderDate as OrderDateASecondTimeForConvenience
FROM
MyCTE outerAlias
ORDER BY outerAlias.OrderDate Desc , OrderId

FIFO Balance at every month end with sql

I am trying to get the balance quantity at the end of every month i.e. running total at every month end with FIFO only but its not showing any result. Pls help
Here is my query.
declare #Stock table (Item char(3) not null,Date date not null,TxnType varchar(3) not null,Qty int not null,Price decimal(10,2) null)
insert into #Stock(Item , [Date] , TxnType, Qty, Price) values
('ABC','20120401','IN', 200, 750.00),
('ABC','20120402','OUT', 100 ,null ),
('ABC','20120403','IN', 50, 700.00),
('ABC','20120404','IN', 75, 800.00),
('ABC','20120405','OUT', 175, null ),
('XYZ','20120406','IN', 150, 350.00),
('XYZ','20120407','OUT', 120 ,null ),
('XYZ','20120408','OUT', 10 ,null ),
('XYZ','20120409','IN', 90, 340.00),
('ABC','20120510','IN', 200, 750.00),
('ABC','20120511','OUT', 100 ,null ),
('ABC','20120512','IN', 50, 700.00),
('ABC','20120513','IN', 75, 800.00),
('ABC','20120514','OUT', 175, null ),
('XYZ','20120515','IN', 150, 350.00),
('XYZ','20120516','OUT', 120 ,null ),
('XYZ','20120517','OUT', 10 ,null ),
('XYZ','20120518','IN', 90, 340.00);
;WITH OrderedIn as (
select *,ROW_NUMBER() OVER (PARTITION BY month(date) ORDER BY DATE) as rn
from #Stock
where TxnType = 'IN'
), RunningTotals as (
select Item,Qty,Price,Qty as Total,0 as PrevTotal,rn from OrderedIn where rn = 1
union all
select rt.Item,oi.Qty,oi.Price,rt.Total + oi.Qty,rt.Total,oi.rn
from
RunningTotals rt
inner join
OrderedIn oi
on
rt.Item = oi.Item and
rt.rn = oi.rn - 1
), TotalOut as (
select Item,SUM(Qty) as Qty from #Stock where TxnType='OUT' group by Item
)
select
rt.Item,SUM(CASE WHEN PrevTotal > out.Qty THEN rt.Qty ELSE rt.Total - out.Qty END * Price)
from
RunningTotals rt
inner join
TotalOut out
on
rt.Item = out.Item
where
rt.Total > out.Qty
group by rt.Item
Output
Month Item (No column name(qty*price))
4 ABC 40000
4 XYZ 37600
5 ABC 77500
5 XYZ 76100
With you sample data.Are you looking for this,else clearly sketch your desired output .
;WITH CTE AS
(
select Item ,[Date] ,TxnType ,s.Qty
,Price ,ROW_NUMBER() OVER (PARTITION BY month(date),TxnType ORDER BY DATE) as rn
from #Stock S
)
,
CTE1 AS
(
SELECT ITEM ,[DATE] ,TXNTYPE ,QTY,MONTH(DATE) MONTHDT,RN FROM CTE WHERE RN=1
UNION ALL
SELECT S.ITEM ,S.[DATE] ,S.TXNTYPE ,S.QTY+A.QTY,A.MONTHDT ,S.RN
FROM CTE S INNER JOIN CTE1 A
ON S.TXNTYPE=A.TXNTYPE AND MONTH(S.[DATE])=A.MONTHDT AND S.RN-A.RN=1
)
,CTE2 AS
(
SELECT *
,ROW_NUMBER() OVER (PARTITION BY month(date),TxnType ORDER BY QTY DESC )RN1
FROM CTE1 S
)
SELECT A.DATE,A.QTY-(SELECT B.Qty from CTE2 B
where a.MONTHDT=b.MONTHDT and b.RN1=1 AND b.TxnType='OUT')
from CTE2 A
WHERE A.RN1=1 AND a.TxnType='IN'
Try this.
;WITH cte
AS (SELECT Row_number()OVER(partition BY item, Datepart(mm, date) ORDER BY date DESC) rn,
item,
Month(date) AS [month],
TxnType,
Price,
date
FROM #Stock
WHERE TxnType = 'IN'),
cte1
AS (SELECT Row_number() OVER(partition BY item, Datepart(mm, date) ORDER BY date DESC) rn,
item,
Month(date) [month],
(SELECT Sum(CASE
WHEN TxnType = 'out' THEN -1 * qty
ELSE qty
END) AS qty
FROM #Stock b
WHERE a.item = b.item
AND a.Date >= b.Date) qty
FROM #Stock a)
SELECT a.[month],
a.Item,
( a.Price * b.qty ) running_tot
FROM cte a
JOIN cte1 b
ON a.Item = b.Item
AND a.[month] = b.[month]
WHERE a.rn = 1
AND b.rn = 1

write query without using cursors

I wrote this query to display single client's account transactions:
select *
from (
select top 1
[id]
,[client_id]
,[transactionDate]
,N'revolving balance' [details]
,NULL [amount]
,NULL [debit]
,NULL [credit]
,[balance]
FROM [dbo].[bsitems]
where [client_id]=#client_id and
[transactionDate] < #transactionDateFrom
order by id desc) t1
union
SELECT [id]
,[client_id]
,[transactionDate]
,[details]
,[amount]
,[debit]
,[credit]
,[balance]
FROM [dbo].[bsitems]
where [client_id]=#client_id and
[transactionDate] between #transactionDateFrom and #transactionDateTo
How to display the transactions for all clients that exists in "client" table? Assume client table structure is (id, name)
For the second part (which is really what the transactions are), just use join:
SELECT b.id, b.client_id, b.transactionDate, b.details,
b.amount, b.debit, b.credit, b.balance
FROM [dbo].[bsitems] b join
clients c
on b.client_id = c.client_id
WHERE transactionDate between #transactionDateFrom and #transactionDateTo;
This assumes that the client_id is stored in the clients table.
The first part of the query is returning the most recent id before the from date. It returns no rows if there are no previous transactions. You can approach this in a similar way.
select id, client_id, transactiondate, details, amount, debit, credit, balance
from (SELECT b.id, b.client_id, b.transactionDate,
N'revolving balance' as b.details,
NULL as b.amount, NULL as b.debit, NULL as b.credit,
b.balance,
row_number() over (partition by client_id order by TransactionDate desc) as seqnum
FROM [dbo].[bsitems] b join
clients c
on b.client_id = c.client_id
WHERE transactionDate < #transactionDateFrom
) t
where seqnum = 1;
Instead of top 1 this is using row_number() to assign a sequential value to the transactions before the cutoff date. Then the most recent of these is chosen.
The final result is just the union all of these two queries:
select id, client_id, transactiondate, details, amount, debit, credit, balance
from (SELECT b.id, b.client_id, b.transactionDate,
N'revolving balance' as b.details,
NULL as b.amount, NULL as b.debit, NULL as b.credit,
b.balance,
row_number() over (partition by client_id order by TransactionDate desc) as seqnum
FROM [dbo].[bsitems] b join
clients c
on b.client_id = c.client_id
WHERE transactionDate < #transactionDateFrom
) t
where seqnum = 1
union all
SELECT b.id, b.client_id, b.transactionDate, b.details,
b.amount, b.debit, b.credit, b.balance
FROM [dbo].[bsitems] b join
clients c
on b.client_id = c.client_id
WHERE transactionDate between #transactionDateFrom and #transactionDateTo;
SELECT *
FROM (
SELECT TOP 1
[id]
,[client_id]
,[transactionDate]
,N'revolving balance' [details]
,NULL [amount]
,NULL [debit]
,NULL [credit]
,[balance]
FROM [dbo].[bsitems]
INNER JOIN [dbo].[client] ON [dbo].[bsitems].[client_id] = [dbo].[client].[id]
AND [transactionDate] < #transactionDateFrom
ORDER BY id DESC
) t1
UNION
SELECT
[id]
,[client_id]
,[transactionDate]
,[details]
,[amount]
,[debit]
,[credit]
,[balance]
FROM [dbo].[bsitems]
INNER JOIN [dbo].[client] ON [dbo].[bsitems].[client_id] = [dbo].[client].[id]
AND [transactionDate] between #transactionDateFrom and #transactionDateTo