how to find count of active sellers from transaction table - sql

from the table given below find the count of active sellers for each day in June 2017. A seller is considered active when he has listed at least one item in last 30 days from the transaction date.
sample table:

Well, one method is to generate the dates and use a lateral join to calculate the number of sellers:
with dates as (
select cast('2017-06-01' as date) as dte
union all
select dateadd(day, 1, dte)
from dates
where dte < '2017-06-30'
)
select d.dte, t.num_sellers
from dates d outer apply
(select count(distinct t.seller_id) as num_sellers
from t
where t.transaction_date > dateadd(day, -30, d.dte) and
t.transaction_date <= d.dte
) t
order by d.dte;

Related

In Postgres how do I write a SQL query to select distinct values overall but aggregated over a set time period

What I mean by this is if I have a table called payments with a created_at column and user_id column I want to select the count of purchases aggregated weekly (can be any interval I want) but only selecting first time purchases e.g. if a user purchased for the first time in week 1 it would be counted but if he purchased again in week 2 he would not be counted.
created_at
user_id
timestamp
1
timestamp
1
This is the query I came up with. The issue is if the user purchases multiple times they are all included. How can I improve this?
WITH dates AS
(
SELECT *
FROM generate_series(
'2022-07-22T15:30:06.687Z'::DATE,
'2022-11-21T17:04:59.457Z'::DATE,
'1 week'
) date
)
SELECT
dates.date::DATE AS date,
COALESCE(COUNT(DISTINCT(user_id)), 0) AS registrations
FROM
dates
LEFT JOIN
payment ON created_at::DATE BETWEEN dates.date AND dates.date::date + '1 ${dateUnit}'::INTERVAL
GROUP BY
dates.date
ORDER BY
dates.date DESC;
You want to count only first purchases. So get those first purchases in the first step and work with these.
WITH dates AS
(
SELECT *
FROM generate_series(
'2022-07-22T15:30:06.687Z'::DATE,
'2022-11-21T17:04:59.457Z'::DATE,
'1 week'
) date
)
, first_purchases AS
(
SELECT user_id, MIN(created_at:DATE) AS purchase_date
FROM payment
GROUP BY user_id
)
SELECT
d.date,
COALESCE(COUNT(p.purchase_date), 0) AS registrations
FROM
dates d
LEFT JOIN
first_purchases p ON p.purchase_date >= d.date
AND p.purchase_date < d.date + '1 ${dateUnit}'::INTERVAL
GROUP BY
d.date
ORDER BY
d.date DESC;

Customers who placed order both in this month and previous month for a list of dates

So I am trying to find count of customers who placed order both in this month and previous month. I have to find this from the beginning of last year. I came up with a query which obviously doesn't work. Can I get some help with this please?
Query:
SELECT DATE_TRUNC('month', month_column), COUNT(DISTINCT(customer_id))
FROM table
WHERE month_column >= '2021-01-01' AND customer_id IN (
SELECT customer_id
FROM table
WHERE month_column = month_column - INTERVAL '1 month')
GROUP BY 1
NOTE: month_column has only month number i.e., '2021-01-01', '2021-02-01' etc.
I am using postgresql.
This is my first stack overflow question. So, if I didn't abide by any rules, I apologize.
To make this trivial, you can use 2 queries. Get customerID's from this month (insert into temp table 1) and customerID's from last month (insert into temp table 2). Lastly just inner join both tables on customerID
something like the below
SELECT customer_id
INTO #thisMonth
FROM customer
WHERE month_column > DATEADD(month, 0, GETDATE())
SELECT customer_id
INTO #prevMonth
FROM customer
WHERE month_column > DATEADD(month, -1, GETDATE())
SELECT COUNT(customer_id)
FROM #thisMonth tm
INNERJOIN #prevMonth pm ON tm.customer_id = pm.customerID

How to replace the loop in MsSQL?

For example
If I want to check in every day last week
select count(ID) from DB where date < "2019/07/01"
select count(ID) from DB where date < "2019/07/02"
select count(ID) from DB where date < "2019/07/03"
...
select count(ID) from DB where date < "2019/07/08"
like
0701 10
0702 15
0703 23
...
0707 45
How to do this without loop and one query?
You can generate the dates using a recursive CTE (or other method) and then run the query:
with dates as (
select convert(date, '2019-07-01') as dte union all
select dateadd(day, 1, dte)
from dates
where dte < '2019-07-08'
)
select d.dte,
(select count(*) from DB where DB.date < d.dte)
from dates d;
More efficient, though, is a cumulative sum:
select db.*
from (select date, count(*) as cnt, sum(count(*)) over (order by date) as running_cnt
from db
group by date
) d
where d.date >= '2019-07-01' and d.date < '2019-07-09';
Are you just counting the number by day?
Something like
SELECT MONTH(date), DAY(date), COUNT(ID)
FROM DB
GROUP BY MONTH(date), DAY(date);
(assuming date is a DATE or DATETIME)
Do it with window Count. range between current row and current row selects exactly this day rows.
select distinct date, count(1) over (order by Date) - count(1) over (order by Date range between current row and current row)
from DB
where date between '2019-07-01' and '2019-07-08';
I assume date column is exactly DATE.

Use a view to determine if a previous date exists

Currently, I have an orders table that I want to extract information from. There are 4 main fields I am looking for: Order no, customer no, date1, and date 2.
Date 1 is the minimum date in the table for a specific customer number prior to the date associated with the order number within a 12 month period (that's not the order number date).
Date 2 is the minimum date in the table for a specific customer number prior to date1 within a 12 month period (that's not date 1)
Here is what I have so far but it doesn't seem to be pulling in any data. Any help is appreciated!
With CTE as
(SELECT Order_no, customer_no, MIN(order_date) AS date1
FROM dbo.orders
WHERE (order_date >= DATEADD(month, - 12, order_date)
and (order_date < DATEADD(day, - 1, order_date)))
GROUP BY Order_no, customer_no)
Select x.order_no, x.customer_no, min(x.order_date) as date2, cte.date1
from dbo.orders x
LEFT OUTER JOIN CTE ON cte.order_no=x.order_no
where x.order_date > DATEADD(month, - 12, cte.date1)
AND x.order_date < DATEADD(DAY, - 1, cte.date1)
Group by x.order_no, x.customer_no, cte.date1
You need to figure out what is filtering based on the data you have. This is more about data meaning than syntax.
Start by making sure the cte is returning any records. and then make sure by checking the data that they are th records you wanted.
With CTE as
(SELECT Order_no, customer_no, MIN(order_date) AS date1
FROM dbo.orders
WHERE (order_date >= DATEADD(month, - 12, order_date)
and (order_date < DATEADD(day, - 1, order_date)))
GROUP BY Order_no, customer_no)
select * from CTE
Once you are sure of this try with just the join
With CTE as
(SELECT Order_no, customer_no, MIN(order_date) AS date1
FROM dbo.orders
WHERE (order_date >= DATEADD(month, - 12, order_date)
and (order_date < DATEADD(day, - 1, order_date)))
GROUP BY Order_no, customer_no)
Select *
from dbo.orders x
LEFT OUTER JOIN CTE ON cte.order_no=x.order_no
Then add the where criteria back in one at a time. This is the basic technique you use when the query does not havea a syntax issue but is not returning the correct data.
Based on the comments, this is what I would try next:
SELECT Order_no, customer_no,order_date, DATEADD(month, - 12, order_date) as ordermonth, DATEADD(day, - 1, order_date) as orderday
FROM dbo.orders
This will tell you why none of your records meet the criteria.

T-SQL recursive in order to find transactions for a period of time

I have tried but i am not able to figure this out. I have a table transactions (transaction_ID, transaction_Person_ID, Transaction_Date etc).
What i want is to return all the transaction_person_ID's that have more than 3 transactions per week for the last year. That means i have to check for 1-1-10 to 7-1-10 to see if someone had more than 3 transactions for that 7 day period, then for 2-1-10 to 8-1-10 then 3-1-10 to 9-1-10 etc etc.
I now i need to use a recursive select but i what i have writen does not produce the correct time frame.
What i have written so far is this
WITH Dates AS (
SELECT
[Date] = CONVERT(DATETIME,'01/01/2010')
UNION ALL SELECT
[Date] = DATEADD(DAY, 1, [Date])
FROM
Dates
WHERE
Date < '12/31/2010'
)
SELECT transaction_person_Id FROM transactions
JOIN DATES
ON transactions.transaction_date = dates.date
where transactions.Transaction_Date between dateadd(DAYOFYEAR,-7,dates.date) and dates.date
group by transaction_person_Id
having count(transaction_person_ID) >= 4
OPTION (MAXRECURSION 2000)
Thanks a lot
PS:
in simple words what i need to do is this
select transaction_person_ID from transactions
where Transaction_Date between '2010-01-01' and '2010-01-07'
group by transaction_person_Id
having count(transaction_person_ID) >= 4
then
select transaction_person_ID from transactions
where Transaction_Date between '2010-01-02' and '2010-01-08'
group by transaction_person_Id
having count(transaction_person_ID) >= 4
.
.
.
.
.
until it goes
select transaction_person_ID from transactions
where Transaction_Date between '2010-12-25' and '2010-12-31'
group by transaction_person_Id
having count(transaction_person_ID) >= 4
i need to have the results of these 365 queries
This will give one result set with person and weeks, rather then 360 results sets
WITH Weeks
AS (
SELECT
CONVERT(DATETIME,'01 Jan 2010') AS WeekStartMidnight,
CONVERT(DATETIME,'08 Jan 2010') AS WeekEndMidnight
UNION ALL
SELECT
DATEADD(day, 1, WeekStartMidnight),
DATEADD(day, 1, WeekEndMidnight)
FROM
Weeks
WHERE
WeekEndMidnight < '31 Dec 2010'
)
SELECT
t.transaction_person_Id,
w.WeekStartMidnight, w.WeekEndMidnight
FROM
weeks w
JOIN
transactions t ON t.Transaction_Date >= w.WeekStartMidnight AND t.Transaction_Date < w.WeekEndMidnight
GROUP BY
t.transaction_person_Id
HAVING
count(*) >= 4 --COUNT(t.transaction_person_Id) = same
OPTION
(MAXRECURSION 365)
If you want 360 results sets, it's a loop using WHILE or a CURSOR per row in the "weeks" derived table