Combine data from a table to one row T-SQL - sql

I have a table in #SQL server 2008 that has transaction data. The table looks like this. I would like to have this in a sql statement.
TransactionId|TransactionDate|TransactionType|Amount|Balance|UserId
The transaction type can be one of four types, Deposit, Withdrawals, Profit and Stake. I give an example how it can look like in the transaction table. The balance is the Sum of amount column.
TransactionId|TransactionDate|TransactionType|Amount|Balance|UserId
1| 2013-03-25| Deposit| 150| 150| 1
2| 2013-03-27| Stake| -20| 130| 1
3| 2013-03-28| Profit | 1500| 1630| 1
4 | 2013-03-29| Withdrawals| -700| 930| 1
5| 2013-03-29| Stake | -230 | 700 | 1
6| 2013-04-04| Stake| -150 | 550| 1
7| 2013-04-06| Stake | -150 | 400| 1
What I want now is to get a select statement that gives me all data grouped by week. The result should look like this.
Week|Deposit|Withdrawals|Stake|Profit|Balance|Year
13 | 150| -700 | -250 | 1500 | 700 | 2013
14 | 0 | 0 | -300| 0 | 400 | 2013
I have also problem with the weeks... I live in Europe an my first day in a week is monday. I have a solution for that but around the end of a year I get sometimes week 54 but there are only 52 weeks in a year...
I hope someone can help me out.
This is what I have so far.
SELECT transactionid,
transactiondate,
transactiontype,
amount,
(SELECT Sum(amount)
FROM transactions AS trans_
WHERE trans_.transactiondate <= trans.transactiondate
AND userid = 1) AS Balance,
userid,
Datepart(week, transactiondate) AS Week,
Datepart(year, transactiondate) AS Year
FROM transactions trans
WHERE userid = 1
ORDER BY transactiondate DESC,
transactionid DESC
Here's sample data and my query on sql-fiddle: http://www.sqlfiddle.com/#!3/79d65/92/0

In order to transform the data from the rows into columns, you will want to use the PIVOT function.
You did not specify what balance value you want to return but based on the final result, it looks like you want the final balance to be the value associated with the last transaction date for each day. If that is not correct, then please clarify what the logic should be.
In order to get the result you will want to use the DATEPART and YEAR functions. These will allow grouping by both the week and year values.
The following query should get the result that you want:
select week,
coalesce(Deposit, 0) Deposit,
coalesce(Withdrawals, 0) Withdrawals,
coalesce(Stake, 0) Stake,
coalesce(Profit, 0) Profit,
Balance,
Year
from
(
select datepart(week, t1.transactiondate) week,
t1.transactiontype,
t2.balance,
t1.amount,
year(t1.transactiondate) year
from transactions t1
cross apply
(
select top 1 balance
from transactions t2
where datepart(week, t1.transactiondate) = datepart(week, t2.transactiondate)
and year(t1.transactiondate) = year(t2.transactiondate)
and t1.userid = t2.userid
order by TransactionId desc
) t2
) d
pivot
(
sum(amount)
for transactiontype in (Deposit, Withdrawals, Stake, Profit)
) piv;
See SQL Fiddle with Demo. The result is:
| WEEK | DEPOSIT | WITHDRAWALS | STAKE | PROFIT | BALANCE | YEAR |
------------------------------------------------------------------
| 13 | 150 | -700 | -250 | 1500 | 700 | 2013 |
| 14 | 0 | 0 | -300 | 0 | 400 | 2013 |
As a side note, you stated that your start of the week is Monday, you might have to use the DATEFIRST function to set the first day of the week.

Another option, without using PIVOT, but rather with few CASEs
WITH CTE AS
(
SELECT
TransactionId
,TransactionDate
,DATEPART(WEEK, TransactionDate) AS Week
,CASE WHEN TransactionType='Deposit' THEN Amount ELSE 0 END AS Deposit
,CASE WHEN TransactionType='Stake' THEN Amount ELSE 0 END AS Stake
,CASE WHEN TransactionType='Profit' THEN Amount ELSE 0 END AS Profit
,CASE WHEN TransactionType='Withdrawals' THEN Amount ELSE 0 END AS Withdrawals
,Balance
,DATEPART(YEAR, TransactionDate) AS Year
FROM dbo.Transactions
)
SELECT
Week, SUM(Deposit) AS Deposit, SUM(Withdrawals) AS Withdrawals, SUM(Stake) AS Stake, SUM(Profit) AS Profit,
(SELECT Balance FROM CTE i WHERE i.TransactionID = MAX(o.TransactionID)) AS BAlance, Year
FROM CTE o
GROUP BY Week, Year
SQLFiddle Demo

http://www.sqlfiddle.com/#!3/79d65/89
;WITH cte AS
(
SELECT datepart(ww, transactiondate) wk,
sum(CASE WHEN TransactionType = 'Deposit' THEN Amount ELSE 0 END) AS D,
sum(CASE WHEN TransactionType = 'Withdrawals' THEN Amount ELSE 0 END) AS W,
sum(CASE WHEN TransactionType = 'Profit' THEN Amount ELSE 0 END) AS P,
sum(CASE WHEN TransactionType = 'Stake' THEN Amount ELSE 0 END) AS S,
sum(
CASE WHEN TransactionType = 'Deposit' THEN Amount ELSE 0 END +
CASE WHEN TransactionType = 'Withdrawals' THEN Amount ELSE 0 END +
CASE WHEN TransactionType = 'Profit' THEN Amount ELSE 0 END +
CASE WHEN TransactionType = 'Stake' THEN Amount ELSE 0 END +
CASE WHEN TransactionType = 'Balance' THEN Amount ELSE 0 END) AS wkTotal
FROM transactions
GROUP BY datepart(ww, transactiondate)),
cte1 AS
(
SELECT *, row_number() over (ORDER BY wk) AS rowNum
FROM cte)
SELECT wk, d, w, p, s, wktotal
+ coalesce((SELECT top 1 wktotal FROM cte1 x WHERE x.rownum < m.rownum ), 0) AS RunningBalance
FROM cte1 m

Related

How do i compare year on change in a SQL database without hardcoding the years?

I have a database with schema such as:
----------------------------------------------
SalesID | ProductID | ProductName | SalesDate
----------------------------------------------
1 | 1 | Football | 2020-01-07
2 | 1 | Football | 2019-01-08
3 | 1 | Football | 2019-01-08
4 | 1 | Football | 2019-01-08
5 | 2 | Racket | 2020-01-07
6 | 2 | Racket | 2018-01-07
7 | 2 | Racket | 2018-01-07
----------------------------------------------
What i want to do is to dynamically retrieve the total year on year change in the amount of sales for each year and its previous year. But in the case where there was no sales for a certain product in one year, then compare it to the next available one.
For example, the "Football" product had 3 sales in 2019 and 1 sale in 2020. So that is a decrease of 66%. And i want to print that.
The "Racket" product had 1 sale in 2020, none in 2019 but 2 in 2018. So i want to print it such that it had a decrease of 50%.
I would like to do this without hardcoding the years using a CASE WHEN statement.
My attempt can get the data i want for each year but if there is year that has no data it compares it anyway to it, instead of comparing it to the next year that contains sales data
declare #maxYear int
declare #minYear int
declare #saleChange int
set #maxYear = (select max(year(SalesDate)) from Products)
set #minYear = (select min(year(SalesDate)) from Products)
create table #temp(
ProductName varchar(255),
CurrentYear int,
CurrentSalesCount int,
PrevYear int,
PrevYrSalesCount int,
Growth int)
WHILE (#maxYear >= #minYear)
BEGIN
insert into #temp
select
d.ProductName,
CurrentYear = #maxYear,
CurrentSalesCount = sum(case when year(d.SalesDate) = #maxYear then 1 else null
end),
PrevYear = #maxYear - 1,
PrevYrSalesCount = sum(case when year(d.SalesDate) = #maxYear - 1 then 1 else null
end),
Growth = (sum(case when year(d.SalesDate) = #maxYear then 1 else null end)
-sum(case when year(d.SalesDate) = #maxYear - 1 then 1 else null end))
from Products d
group by
d.ProductName
Set #maxYear = #maxYear - 1
END
select * from #temp
You may try below query, tested at dbfiddle
SELECT
pid as ProductId,
salyr as SaleYear,
cnt as SaleCount,
LAG(cnt, 1, 0) OVER (PARTITION BY pid ORDER BY salyr) AS PrevYearSale,
cnt - LAG(cnt, 1, 0) OVER (PARTITION BY pid ORDER BY salyr) AS DiffPrevYear,
case when LAG(cnt, 1, 0) OVER (PARTITION BY pid ORDER BY salyr) = 0 then 0
else
round((cnt - LAG(cnt, 1, 0) OVER (PARTITION BY pid ORDER BY salyr))*100
/(LAG(cnt, 1, 0) OVER (PARTITION BY pid ORDER BY salyr)),2) end as PerDifference
FROM
(Select productid as pid,
extract(year from salesdate) as salyr,
count(1) as cnt
from test
group by productid, extract(year from salesdate)
order by 1, 2)
;
Use aggregation and window functions:
select year(salesdate), product, count(*) as cnt
lag(count(*)) over (partition by product order by year(salesdate)) as prev_cnt,
(count(*) * 1.0 /
lag(count(*)) over (partition by product order by year(salesdate))
) as ratio
from t
group by year(salesdate);

Postgres Bank Account Transaction Balance

Here's an example "transactions" table where each row is a record of an amount and the date of the transaction.
+--------+------------+
| amount | date |
+--------+------------+
| 1000 | 2020-01-06 |
| -10 | 2020-01-14 |
| -75 | 2020-01-20 |
| -5 | 2020-01-25 |
| -4 | 2020-01-29 |
| 2000 | 2020-03-10 |
| -75 | 2020-03-12 |
| -20 | 2020-03-15 |
| 40 | 2020-03-15 |
| -50 | 2020-03-17 |
| 200 | 2020-10-10 |
| -200 | 2020-10-10 |
+--------+------------+
The goal is to return one column "balance" with the balance of all transactions. Only catch is that there is a monthly fee of $5 for each month that there are not at least THREE payment transactions (represented by a negative value in the amount column) that total at least $100. So in the example, the only month where you wouldn't have a $5 fee is March because there were 3 payments (negative amount transactions) that totaled $145. So the final balance would be $2,746. The sum of the amounts is $2,801 minus the $55 monthly fees (11 months X 5). I'm not a postgres expert by any means, so if anyone has any pointers on how to get started solving this problem or what parts of the postgres documentation which help me most with this problem that would be much appreciated.
The expected output would be:
+---------+
| balance |
+---------+
| 2746 |
+---------+
This is rather complicated. You can calculate the total span of months and then subtract out the one where the fee is cancelled:
select amount, (extract(year from age) * 12 + extract(month from age)), cnt,
amount - 5 *( extract(year from age) * 12 + extract(month from age) + 1 - cnt) as balance
from (select sum(amount) as amount,
age(max(date), min(date)) as age
from transactions t
) t cross join
(select count(*) as cnt
from (select date_trunc('month', date) as yyyymm, count(*) as cnt, sum(amount) as amount
from transactions t
where amount < 0
group by yyyymm
having count(*) >= 3 and sum(amount) < -100
) tt
) tt;
Here is a db<>fiddle.
This calculates 2756, which appears to follow your rules. If you want the full year, you can just use 12 instead of the calculating using the age().
I would first left join with a generate_series that represents the months you are interested in (in this case, all in the year 2020). That adds the missing months with a balance of 0.
Then I aggregate these values per month and add the negative balance per month and the number of negative balances.
Finally, I calculate the grand total and subtract the fee for each month that does not meet the criteria.
SELECT sum(amount_per_month) -
sum(5) FILTER (WHERE negative_per_month > -100 OR negative_count < 3)
FROM (SELECT sum(amount) AS amount_per_month,
sum(amount) FILTER (WHERE amount < 0) AS negative_per_month,
month_start,
count(*) FILTER (WHERE amount < 0) AS negative_count
FROM (SELECT coalesce(t.amount, 0) AS amount,
coalesce(date_trunc('month', CAST (t.day AS timestamp)), dates.d) AS month_start
FROM generate_series(
TIMESTAMP '2020-01-01',
TIMESTAMP '2020-12-01',
INTERVAL '1 month'
) AS dates (d)
LEFT JOIN transactions AS t
ON dates.d = date_trunc('month', CAST (t.day AS timestamp))
) AS gaps_filled
GROUP BY month_start
) AS sums_per_month;
This would be my solution by simply using cte.
DB fiddle here.
balance
2746
Code:
WITH monthly_credited_transactions
AS (SELECT Date_part('month', date) AS cred_month,
Sum(CASE
WHEN amount < 0 THEN Abs(amount)
ELSE 0
END) AS credited_amount,
Sum(CASE
WHEN amount < 0 THEN 1
ELSE 0
END) AS credited_cnt
FROM transactions
GROUP BY 1),
credit_fee
AS (SELECT ( 12 - Count(1) ) * 5 AS fee,
1 AS id
FROM monthly_credited_transactions
WHERE credited_amount >= 100
AND credited_cnt >= 3),
trans
AS (SELECT Sum(amount) AS amount,
1 AS id
FROM transactions)
SELECT amount - fee AS balance
FROM trans a
LEFT JOIN credit_fee b
ON a.id = b.id
For me the below query worked (have adopted my answer from #GordonLinoff):
select CAST(totalamount - 5 *(12 - extract(month from firstt) + 1 - nofeemonths) AS int) as balance
from (select sum(amount) as totalamount, min(date) as firstt
from transactions t
) t cross join
(select count(*) as nofeemonths
from (select date_trunc('month', date) as months, count(*) as nofeemonths, sum(amount) as totalamount
from transactions t
where amount < 0
group by months
having count(*) >= 3 and sum(amount) < -100
) tt
) tt;
The firstt is the date of first transaction in that year and 12 - extract(month from firstt) + 1 - nofeemonths are the number of months for which the credit card fees of 5 will be charged.

SSRS Expression "Count of Days with No dissatisfied Customers" Cannot get it working

I have to get a expression in my SSRS table that achieves the count of days with no dissatisfied customers.
Right now I have an expression like this:
=RunningValue(IIF(Fields!SATISFACTION_LEVEL.Value <> "Dissatisfied",1,0),Sum, "DataSet1")
This gives me the number of rows that contain a satisfaction level other than Dissatisfied.
My issue is that I can't seem to get a count of days where there was no dissatisfied customer. I can't find a solution to counting the days. Essentially this is what it should do. If there was a record that day with a dissatisfied customer, don't count it. If there was no dissatisfied customers, tally it.
This will need to be done for the current year to date, and also for the year before.
I would really appreciate any help with this expression!
Thanks
UPDATE MORE INFO:
dataset structure is like this:
_______________________________________
| satisfaction_level | Date |
---------------------------------------
| Satisfied | 07/20/2020 |
| dissatisfied | 07/20/2020 |
| Satisfied | 07/20/2020 |
| Highly Satisfied | 07/20/2020 |
| Satisfied | 07/20/2020 |
| Satisfied | 07/21/2020 |
| Satisfied | 07/21/2020 |
| Highly Satisfied | 07/21/2020 |
expected functionality - for the day of 7/20/2020 there was 1 dissatisfied customer (do not tally), for the day of 7/21/2020 there were NO dissatisfied customers (tally). Resulting in a total number of days where there were NO dissatisfied customers. I hope this helps further explain the outcome needed.
Put SSRS to the side for now, the problem with counting days of anything is that its hard to count a row that is not there. For instance if I have a number of response records spread out over a week, but they only fall on 4 of the days, when we group by day, the query can only return results for the days that existed in the recordset:
DECLARE #Responses as Table
(
ENTRY_TIME DateTimeOffset, SATISFACTION_LEVEL VARCHAR(20)
)
INSERT INTO #Responses
VALUES
('2020-01-4', 'Dissatisfied'),
('2020-01-4', 'Dissatisfied'),
('2020-01-1', 'Satisfied'),
('2020-01-5', 'Dissatisfied'),
('2020-01-5', 'Satisfied'),
('2020-01-2', 'Dissatisfied')
SELECT
fn.DATE
, DATENAME(WEEKDAY, fn.DATE) as [Day]
, SUM(CASE SATISFACTION_LEVEL WHEN 'Dissatisfied' THEN 1 ELSE 0 END) as [Dissatisfied]
FROM #Responses
CROSS APPLY (SELECT CAST(ENTRY_TIME as Date) as [DATE]) as fn
GROUP BY fn.DATE
ORDER BY fn.DATE
DATE Day Dissatisfied
---------- ------------------------------ ------------
2020-01-01 Wednesday 0
2020-01-02 Thursday 1
2020-01-04 Saturday 2
2020-01-05 Sunday 1
(4 rows affected)
We can solve this problem by generating a series record set that we can join our real world data against that will ensure that we have a row for each day.
This can be achieved through the use of a recursive CTE, in the query below the grouped data result is joined to the series data, you could do this any number of different ways, you could even pivot the SATISFACTION_LEVEL column responses, this is just to illustrate
the technique of pre-processing the data in SQL before formatting it in an SSRS report:
DECLARE #From Date = '2019-12-30';
DECLARE #To Date = '2020-01-05';
;
WITH [Sequence] ([Date])
as
(
SELECT #From
UNION ALL
SELECT DATEADD(DAY, 1, [Date]) FROM [Sequence]
WHERE [Date] < #To
)
, [GroupedByDay]
as
(
SELECT
fn.DATE
, SUM(CASE SATISFACTION_LEVEL WHEN 'Dissatisfied' THEN 1 ELSE 0 END) as [Dissatisfied]
, SUM(CASE SATISFACTION_LEVEL WHEN 'Satisfied' THEN 1 ELSE 0 END) as [Satisfied]
FROM #Responses
CROSS APPLY (SELECT CAST(ENTRY_TIME as Date) as [DATE]) as fn
GROUP BY fn.DATE
)
SELECT
c.[Date]
, DATENAME(WEEKDAY, c.[DATE]) as [Day]
, ISNull([Dissatisfied],0) as [Dissatisfied]
, ISNULL([Satisfied],0) as [Satisfied]
FROM [GroupedByDay] g
RIGHT OUTER JOIN [Sequence] c ON g.[DATE] = c.[Date]
ORDER BY c.[Date]
Date Day Dissatisfied Satisfied
---------- ------------------------------ ------------ -----------
2019-12-30 Monday 0 0
2019-12-31 Tuesday 0 0
2020-01-01 Wednesday 0 1
2020-01-02 Thursday 1 0
2020-01-03 Friday 0 0
2020-01-04 Saturday 2 0
2020-01-05 Sunday 1 1
(7 rows affected)
Without specific information about your schema and current query, that's about the best I can offer, however data by day should be more than enough for you group this into year on year results within SSRS...
Or you could do it directly in SQL too if you want :)
#Update: Example where just the total count of days where there are no dissatisfied customers is returned:
DECLARE #From Date = '2019-12-30';
DECLARE #To Date = '2020-01-05';
;
WITH [Sequence] ([Date])
as
(
SELECT #From
UNION ALL
SELECT DATEADD(DAY, 1, [Date]) FROM [Sequence]
WHERE [Date] < #To
)
, [GroupedByDay]
as
(
SELECT
fn.DATE
, SUM(CASE SATISFACTION_LEVEL WHEN 'Dissatisfied' THEN 1 ELSE 0 END) as [Dissatisfied]
, SUM(CASE SATISFACTION_LEVEL WHEN 'Satisfied' THEN 1 ELSE 0 END) as [Satisfied]
FROM #Responses
CROSS APPLY (SELECT CAST(ENTRY_TIME as Date) as [DATE]) as fn
GROUP BY fn.DATE
)
, [InjectedMissingDays]
as
(
SELECT
c.[Date]
, DATENAME(WEEKDAY, c.[DATE]) as [Day]
, ISNull([Dissatisfied],0) as [Dissatisfied]
, ISNULL([Satisfied],0) as [Satisfied]
FROM [GroupedByDay] g
RIGHT OUTER JOIN [Sequence] c ON g.[DATE] = c.[Date]
)
--Overall
SELECT COUNT(1) as [Days with No Dissatisfied Customers] FROM [InjectedMissingDays] WHERE Dissatisfied = 0
Days with No Dissatisfied Customers
-----------------------------------
4
(1 row affected)

Aggregate a subtotal column based on two dates of that same row

Situation:
I have 5 columns
id
subtotal (price of item)
order_date (purchase date)
updated_at (if refunded or any other status change)
status
Objective:
I need the order date as column 1
I need to get the subtotal for each day regardless if of the status as column 2
I need the subtotal amount for refunds for the third column.
Example:
If a purchase is made on May 1st and refunded on May 3rd. The output should look like this
+-------+----------+--------+
| date | subtotal | refund |
+-------+----------+--------+
| 05-01 | 10.00 | 0.00 |
| 05-02 | 00.00 | 0.00 |
| 05-03 | 00.00 | 10.00 |
+-------+----------+--------+
while the row will look like that
+-----+----------+------------+------------+----------+
| id | subtotal | order_date | updated_at | status |
+-----+----------+------------+------------+----------+
| 123 | 10 | 2019-05-01 | 2019-05-03 | refunded |
+-----+----------+------------+------------+----------+
Query:
Currently what I have looks like this:
Note: Timezone discrepancy therefore bring back the dates by 8 hours.
;with cte as (
select id as orderid
, CAST(dateadd(hour,-8,order_date) as date) as order_date
, CAST(dateadd(hour,-8,updated_at) as date) as updated_at
, subtotal
, status
from orders
)
select
b.dates
, sum(a.subtotal_price) as subtotal
, -- not sure how to aggregate it to get the refunds
from Orders as o
inner join cte as a on orders.id=cte.orderid
inner join (select * from cte where status = ('refund')) as b on o.id=cte.orderid
where dates between '2019-05-01' and '2019-05-31'
group by dates
And do I need to join it twice? Hopefully not since my table is huge.
This looks like a job for a Calendar Table. Bit of a stab in the dark, but:
--Overly simplistic Calendar table
CREATE TABLE dbo.Calendar (CalendarDate date);
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
FROM N N1, N N2, N N3, N N4, N N5) --Many years of data
INSERT INTO dbo.Calendar
SELECT DATEADD(DAY, T.I, 0)
FROM Tally T;
GO
SELECT C.CalendarDate AS [date],
CASE C.CalendarDate WHEN V.order_date THEN subtotal ELSE 0 END AS subtotal,
CASE WHEN C.CalendarDate = V.updated_at AND V.[status] = 'refunded' THEN subtotal ELSE 0.00 END AS subtotal
FROM (VALUES(123,10.00,CONVERT(date,'20190501'),CONVERT(date,'20190503'),'refunded'))V(id,subtotal,order_date,updated_at,status)
JOIN dbo.Calendar C ON V.order_date <= C.CalendarDate AND V.updated_at >= C.CalendarDate;
GO
DROP TABLE dbo.Calendar;
Consider joining on a recursive CTE of sequential dates:
WITH dates AS (
SELECT CONVERT(datetime, '2019-01-01') AS rec_date
UNION ALL
SELECT DATEADD(d, 1, CONVERT(datetime, rec_date))
FROM dates
WHERE rec_date < '2019-12-31'
),
cte AS (
SELECT id AS orderid
, CAST(dateadd(hour,-8,order_date) AS date) as order_date
, CAST(dateadd(hour,-8,updated_at) AS date) as updated_at
, subtotal
, status
FROM orders
)
SELECT rec_date AS date,
CASE
WHEN c.order_date = d.rec_date THEN subtotal
ELSE 0
END AS subtotal,
CASE
WHEN c.updated_at = d.rec_date THEN subtotal
ELSE 0
END AS refund
FROM cte c
JOIN dates d ON d.rec_date BETWEEN c.order_date AND c.updated_at
WHERE c.status = 'refund'
option (maxrecursion 0)
GO
Rextester demo

Selecting a row based on a field value on the 1st of the month in SQL

In the below table I want to select a row where "Days" = 1 but the account should have Days = 0 on the 1st of the month.
Account| Date | Days
-------|------|-----
A | 1/3/2015 | 0
A | 5/3/2015 | 1
A | 9/3/2015 | 10
B | 1/3/2015 | 30
B | 3/3/2015 | 1
B | 6/3/2015 | 12
The result should be 2nd row
A 5/3/2015 1
On the 1st A has 0 days but B has 30 days hence I want only account A
This code is for ORACLE, but take a look. Idea is:
SELECT *
FROM ACCOUNTS
WHERE DAYS = 1
AND ACC IN (SELECT ACCOUNT
FROM ACCOUNTS
WHERE ACC_DATE = TRUNC (ACC_DATE, 'MONTH') AND DAYS = 0)
Try to convert to MSSQL and run.
Try this using window function max with case to find out if there is a row with day = 1 and Days = 0 and if there is, return second row using row_number in the order of increasing date for that account in that month.
select *
from (
select
t.*,
max(case when day(date) = 1 and Days = 0 then 1 end)
over (partition by Account, month(Date), year(Date)) flag,
row_number() over (
partition by Account, month(Date), year(Date)
order by Date
) rn
from your_table t
) t where flag = 1 and rn = 2
You could try this:
SELECT account, date, days
FROM table_name t
WHERE days = 1
AND EXISTS (SELECT 1
FROM table_name
WHERE account = t.account
AND date = DATEADD(month, DATEDIFF(month, 0, t.date), 0)
--cast(date As Date) = DATEADD(month, DATEDIFF(month, 0, t.date), 0)
AND days = 0);