Current date and past 30 days total value - sql

The code I currently have shows me the current value for everyday and gives the running total.
select t.lgl_entity_nm, d.date_key,
count(distinct s.site_key) AS Dis,
SUM(Dis) over (partition by t.lgl_entity_nm order by d.date_key ASC rows unbounded preceding) RunningTotal
from site_v s
join touchpoint_v t
on s.site_key = t.site_key
join omni_promo_varnt_fact_v o
on o.touchpoint_key = t.touchpoint_key
join date_v d
on d.date_key = o.date_key
where d.date_key between 20190901 and 20190931
and t.lgl_entity_nbr = 1
and tot_selected_qty > 0
and event_typ_cd in ('IS-SPRINT-T', 'IS-PRINT-T')
group by 1,2
Giving me this output:
lgl_entity_nm date_key dis runningtotal
Ahold USA 20190901 729 729
Ahold USA 20190902 733 1462
If you look at the date its set between a certain time period. What I want achieve is that it shows me the current date or any set date value and past 30 days total in a single row. Suppose the date is 2019-09-30:
lgl_entity_nm date_key(current date) dis total (past30 days)
Ahold USA 20190930 739 21953
Can this be achieved? If so how?

Try this?
DECLARE #CurrentDate DATE = GETDATE()
,#MonthBack DATE = DATEADD(DAY,-30,GETDATE())
SELECT t.lgl_entity_nm
,#CurrentDate AS CurrentDate
,COUNT(DISTINCT s.site_key) AS Dis
,SUM(Dis) AS RunningTotal
FROM site_v AS s
JOIN touchpoint_v AS t ON s.site_key = t.site_key
JOIN omni_promo_varnt_fact_v AS o ON o.touchpoint_key = t.touchpoint_key
JOIN date_v AS d ON d.date_key = o.date_key
WHERE d.date_key BETWEEN #MonthBack AND #CurrentDate
AND t.lgl_entity_nbr = 1
AND tot_selected_qty > 0
AND event_typ_cd IN ('IS-SPRINT-T', 'IS-PRINT-T')
GROUP BY
t.lgl_entity_nm

I think you can just remove the date key from the aggregation:
select t.lgl_entity_nm, max(d.date_key),
count(distinct s.site_key) as as RunningTotal
from site_v s join
touchpoint_v t
on s.site_key = t.site_key join
omni_promo_varnt_fact_v o join
on o.touchpoint_key = t.touchpoint_key join
date_v d
on d.date_key = o.date_key
where d.date_key between 20190901 and 20190931 and
t.lgl_entity_nbr = 1 and
tot_selected_qty > 0 and
event_typ_cd in ('IS-SPRINT-T', 'IS-PRINT-T')
group by 1;
Actually, this subtly different from your query, because you are not counting distinct site_key over the entire period, but adding up the distinct counts per day. For that:
count(distinct d.date_key || ':' || s.site_key) as RunningTotal

Related

SELECT list expression references column integration_start_date which is neither grouped nor aggregated at

I'm facing an issue with the following query. It gave me this error [SELECT list expression references column integration_start_date which is neither grouped nor aggregated at [34:63]]. In particular, it points to the first 'when' in the result table, which I don't know how to fix. This is on BigQuery if that helps. I see everything is written correctly or I could be wrong. Seeking for help.
with plan_data as (
select format_date("%Y-%m-%d",last_day(date(a.basis_date))) as invoice_date,
a.sponsor_id as sponsor_id,
b.company_name as sponsor_name,
REPLACE(SUBSTR(d.meta,STRPOS(d.meta,'merchant_id')+12,13),'"','') as merchant_id,
a.state as plan_state,
date(c.start_date) as plan_start_date,
a.employee_id as square_employee_id,
date(
(select min(date)
from glproductionview.stats_sponsors
where sponsor_id = a.sponsor_id and sponsor_payroll_provider_identifier = 'square' and date >= c.start_date) )
as integration_start_date,
count(distinct a.employee_id) as eligible_pts_count, --pts that are in active plan and have payroll activities (payroll deductions) in the reporting month
from glproductionview.payroll_activities as a
left join glproductionview.sponsors as b
on a.sponsor_id = b.id
left join glproductionview.dc_plans as c
on a.plan_id = c.id
left join glproductionview.payroll_connections as d
on a.sponsor_id = d.sponsor_id and d.provider_identifier = 'rocket' and a.company_id = d.payroll_id
where a.payroll_provider_identifier = 'rocket'
and format_date("%Y-%m",date(a.basis_date)) = '2021-07'
and a.amount_cents > 0
group by 1,2,3,4,5,6,7,8
order by 2 asc
)
select invoice_date,
sponsor_id,
sponsor_name,
eligible_pts_count,
case
when eligible_pts_count <= 5 and date_diff(current_date(),integration_start_date, month) <= 12 then 20
when eligible_pts_count <= 5 and date_diff(current_date(),integration_start_date, month) > 12 then 15
when eligible_pts_count > 5 and date_diff(current_date(),integration_start_date, month) <= 12 then count(distinct square_employee_id)*4
when eligible_pts_count > 5 and date_diff(current_date(),integration_start_date, month) > 12 then count(distinct square_employee_id)*3
else 0
end as fees
from plan_data
group by 1,2,3,4;

List count for last 12 months broken down by month

I have a query that can get a total active count of products until a specified date #POINT
SELECT
COUNT(DISTINCT e.productId) CNT
FROM
pro p
OUTER APPLY (
SELECT
TOP 1 p2.*
FROM
pro p2
WHERE
p2.productId = p.productId
AND p2.date >= #POINT
AND p2.STATUS IN ('SOLD', 'ACTIVE')
ORDER BY
p2.date ASC
) NEXT
WHERE
p.date < #POINT
AND p.STATUS = 'SOLD'
AND NEXT.productId IS NOT NULL
Output for #POINT "01/01/2021" is
CNT
500
From a table like
productId date STATUS
1001 01/04/2021 ACTIVE
1002 01/06/2021 SOLD
1003 01/07/2021 OTHER
...
How would I remake this query so that I can have a list of points (last 12 months) like
POINT CNT
02/01/2021 550
01/01/2021 500
12/01/2020 450
...
03/01/2020 550
in one query? I don't want to create a separate table of dates. The database is MSSQL.
Since no responded to question, I'll assume there isn't a function to generate these dates efficiently. I wrote a subquery that CAST couple dates to varchar to date, resulting with first months for the past 12 months.
Just group it by the Point and COUNT(*) the result.
You say in your update "CAST couple dates to varchar to date", which I think means you want just the date part, in which case you can use CAST(NEXT.date AS date):
SELECT
NEXT.date POINT, -- or CAST(NEXT.date AS date)
COUNT(*) CNT
FROM
pro p
OUTER APPLY (
SELECT
TOP 1 p2.*
FROM
pro p2
WHERE
p2.productId = p.productId
AND p2.date >= #POINT
AND p2.STATUS IN ('SOLD', 'ACTIVE')
ORDER BY
p2.date ASC
) NEXT
WHERE
p.date < #POINT
AND p.STATUS = 'SOLD'
AND NEXT.productId IS NOT NULL
GROUP BY
NEXT.date; -- or CAST(NEXT.date AS date)

Fill in blank dates for rolling average - CTE in Snowflake

I have two tables – activity and purchase
Activity table:
user_id date videos_watched
1 2020-01-02 3
1 2020-01-04 5
1 2020-01-07 5
Purchase table:
user_id purchase_date
1 2020-01-01
2 2020-02-02
What I would like to do is to get a 30 day rolling average since purchase on how many videos has been watched.
The base query is like this:
SELECT
DATEDIFF(DAY, p.purchase_date, a.date) AS day_since_purchase,
AVG(A.VIDEOS_VIEWED)
FROM PURCHASE P
LEFT OUTER JOIN ACTIVITY A ON P.USER_ID = A.USER_ID AND
A.DATE >= P.PURCHASE_DATE AND A.DATE <= DATEADD(DAY, 30, P.PURCHASE_DATE)
GROUP BY 1;
However, the Activity table only has records for each day a video has been logged. I would like to fill in the blanks for days a video has not been viewed.
I have started to look into using a CTE like this:
WITH cte AS (
SELECT date('2020-01-01') as fdate
UNION ALL
SELECT CAST(DATEADD(day,1,fdate) as date)
FROM cte
WHERE fdate < date('2020-04-01')
) select * from cte
cross join purchases p
left outer join activity a
on p.user id = a.user_id
and a.fdate = p.purchase_date
and a.date >= p.purchase_date and a.date <= dateadd(day, 30, p.purchase_date)
The end goal is to have something like this:
days_since_purchase videos_watched
1 3
2 0 --CTE coalesce inserted value
3 0
4 5
Been trying for the last couple of hours to get it right, but still can't really get the hang of it.
If you want to fill in the gaps in the result set, then I think you should be generating integers rather than dates:
WITH cte AS (
SELECT 1 as day_since_purchase
UNION ALL
SELECT 1 + day_since_purchase
FROM cte
WHERE day_since_purchase < 4
)
SELECT cte.day_since_purchase, COALESCE(avg_videos_viewed, 0)
FROM cte LEFT JOIN
(SELECT DATEDIFF(DAY, p.purchase_date, a.date) AS day_since_purchase,
AVG(A.VIDEOS_VIEWED) as avg_videos_viewed
FROM purchases p JOIN
activity a
ON p.user id = a.user_id AND
a.fdate = p.purchase_date AND
a.date >= p.purchase_date AND
a.date <= dateadd(day, 30, p.purchase_date)
GROUP BY 1
) pa
ON pa.day_since_purchase = cte.day_since_purchase;
You can use a recursive query to generate the 30 days following each purchase, then bring the activity table:
with cte as (
select
purchase_date,
client_id,
0 days_since_purchase,
purchase_date dt
from purchases
union all
select
purchase_date,
client_id,
days_since_purchase + 1
dateadd(day, days_since_purchase + 1, purchase_date)
from cte
where days_since_purchase < 30
)
select
c.days_since_purchase,
avg(colaesce(a. videos_watch, 0)) avg_ videos_watch
from cte c
left join activity a
on a.client_id = c.client_id
and a.fdate = c.purchase_date
and a.date = c.dt
group by c.days_since_purchase
Your question is unclear on whether you have a column in the activity table that stores the purchase date each row relates to. Your query has column fdate but not your sample data. I used that column in the query (without such column, you might end up counting the same activity in different purchases).

Simplify complex Query

I need to simplify a complex old query in order to filter is with date range.
I got a table with Tickets and TicketNotes.
I need
a column with the Tickets count of the day
a column with the Tickets count with a specific note of the day
the date
The old query
SELECT SUM(IFNULL(qtickets.count, 0)) j, SUM(IFNULL(mtickets.count, 0)) m FROM (
SELECT
COUNT(tickets.id) COUNT,
DATE(tickets.date) DATE
FROM
tickets
WHERE
tickets.status = 'Closed' AND tickets.did = 7
AND MONTH(tickets.date) = MONTH( CURRENT_DATE - INTERVAL 1 MONTH )
AND YEAR(tickets.date) = YEAR( CURRENT_DATE - INTERVAL 1 MONTH )
GROUP BY
DATE(tickets.date)
) AS mtickets LEFT JOIN (
SELECT
1 AS COUNT,
DATE(tickets.date) DATE
FROM
ticketnotes
INNER JOIN tickets ON tickets.id = ticketnotes.ticketid
WHERE
ticketnotes.message LIKE '%https://xxxxx.net/help/tickets/%'
AND tickets.status = 'Closed'
AND tickets.did = 7
AND MONTH(tbltickets.date) = MONTH( CURRENT_DATE - INTERVAL 1 MONTH )
AND YEAR(tbltickets.date) = YEAR( CURRENT_DATE - INTERVAL 1 MONTH )
GROUP BY
DATE(tickets.date)
) AS qtickets ON (mtickets.date = qtickets.date)
The goal is to get a result of
Date | M | Q
===================
2020-04-01 | 1 | 1
2020-04-02 | 2 | 1
2020-04-03 | 5 | 2
...
2020-04-30 | 3 | 0
With M be the total closed tickets of the day for did = 7 and Q be the total closed tickets that got the note.message.
I need to check the query with one instance of date filter date BETWEEN '2020-04-01' AND '2020-04-30' and still get the correct three columns.
=======
UPDATE:
When I'm trying to add AND DATE(tickets.date) BETWEEN DATE('2020-04-01') AND DATE('2020-04-30') in Gordon's answer, I got other result data from my primary query.
QUERY:
SELECT
DATE(t.date),
COUNT(t.id) AS num_tickets,
(CASE WHEN COUNT(tn.ticketid) = 0 THEN 0 ELSE 1 END) AS num_with_message
FROM
tickets t
LEFT JOIN ticketnotes tn ON
tn.ticketid = t.id AND tn.message LIKE '%https://xxxxx.net/help/tickets/%'
WHERE
t.status = 'Closed' AND t.did = 7
AND DATE(t.date) BETWEEN DATE('2020-04-01') AND DATE('2020-04-30')
GROUP BY
DATE(t.date)
The result is getting num_tickets with wrong data as getting num_ticket without JOIN.
Any suggestions ?
You could try using case for the ehere like
SELECT
DATE(tickets.date) DATE
, COUNT(tickets.id) M
, case sum( ticketnotes.message LIKE '%https://xxxxx.net/help/tickets/%' <> 0 ) then 1 else null end Q
FROM
ticketnotes
INNER JOIN tickets ON tickets.id = ticketnotes.ticketid
WHERE tickets.status = 'Closed'
AND tickets.did = 7
AND MONTH(tbltickets.date) = MONTH( CURRENT_DATE - INTERVAL 1 MONTH )
AND YEAR(tbltickets.date) = YEAR( CURRENT_DATE - INTERVAL 1 MONTH )
GROUP BY DATE(tickets.date)
This answers the original version of the question.
What you are describing sounds like a group by with left join. However, it is not clear what exactly you are looking for. My best guess is:
select date(t.date), count(t.id) as num_tickets,
count(tn.ticketid) as num_with_message
from tickets t left join
ticketnotes tn
on tn.ticketid = t.id and
tn.message like '%https://xxxxx.net/help/tickets/%'
where t.status = 'Closed' and
t.did = 7
group by date(t.date)

How do you calculate a time difference between 2 different rows in the same table?

I want to calculate the difference between 2 date fields in the same table, however the values are not in the same row. An example table is below
ID Cust_ID Code Order_Time Delivery_Time Duration
1 4 Order 01/01/15 14:15
2 5 order 02/02/15 18:30
3 4 deliver 03/02/15 18:15 28:00
4 6 order 04/02/15 16:22
I need to calculate the time taken (Duration) in hours to deliver the order by subtracting the order time for Cust_ID 4 from the delivery_time for this customer. In the example above I have entered the figure as 28 hours.
SELECT t._cust_id, MAX(order_time) order_time, MAX(delivery_time) delivery_time, MAX(delivery_time) - MAX(order_time) as diff_time
FROM yourTable t
WHERE t.cust_id = 4
GROUP BY t.cust_id
or
SELECT
o.order_time, d.delivery_time, d.delivery_time - o.order_time as diff_time
FROM yourTable o, yourTable d
WHERE LOWER(o.code) = 'order'
and LOWER(d.code) = 'deliver'
AND o.cust_id = d.cust_id
GROUP BY o._cust_id
----- for updating the table -----
can you check if the following works ? I am not sure...
UPDATE
(
SELECT
o.order_time, t.delivery_time order_delivery_time, d.delivery_time, d.delivery_time - o.order_time as diff_time
FROM yourTable o, yourTable d
WHERE LOWER(o.code) = 'order'
and LOWER(d.code) = 'deliver'
AND o.cust_id = d.cust_id
GROUP BY o._cust_id
) t
SET
t.order_delivery_time = t.diff_time
So thanks to Veverke who really helped me with not only this query but a better understanding of what I can do in SQL (self-join).
This is the SELECT query that worked:
SELECT
d.delivery_time - o.order_time as diff_time
FROM yourTable o, yourTable d
WHERE o.code = 'order'
AND d.code = 'deliver'
AND o.cust_id = d.cust_id
GROUP BY o.cust_id, d.delivery_time,o.order_time
ORDER BY o.cust_id;