Trying to find 12 week average by weekday basis - sql

I am trying to find 12 weeks average through same weekday.
Example:
weekday sale
So basically I need the average based on the number of stores having net > 0. for yellow color, it should be total/11 as there is no sale for 02-07-16
I have written this query but it doesn't work properly. Could you guys please help me?
SELECT Store_DateJoined.StoreKey, Store_DateJoined.RestaurantName, Store_DateJoined.Ownership, Store_DateJoined.DateKey,
Sales_Summary.Net, Sales_Summary.[LastWeek_Net],
(SELECT AVG(Net) AS AVGNET
FROM (SELECT TOP (12) Net
FROM DailySummary AS FB INNER JOIN
DimDate ON FB.DateKey = DimDate.DateKey
WHERE datename(WEEKDAY, TransactionDate) IN (select datename(WEEKDAY, TransactionDate) from [NandosDW].[dbo].[DailySummary]) and (FB.StoreKey = Store_DateJoined.StoreKey) AND (FB.DateKey <= Store_DateJoined.DateKey) AND
(DimDate.DayNameOfWeek = Store_DateJoined.DayNameOfWeek) AND (FB.DateKey >= (FB.DateKey - 84))
ORDER BY FB.DateKey, StoreKey DESC) AS WAVGNET) AS [Week12_Net],
Store_DateJoined.FullDate, Store_DateJoined.DayNameOfWeek, Store_DateJoined.FinancialWC, Store_DateJoined.strFinancialWeek
FROM Sales_Summary RIGHT OUTER JOIN Store_DateJoined LEFT OUTER JOIN
DimLFL ON Store_DateJoined.StoreKey = DimLFL.StoreKey AND Store_DateJoined.DateKey = DimLFL.DateKey ON
Sales_Summary.RedCatID = Sore_DateJoined.StoreKey AND
Sales_Summary.DateKey = Store_DateJoined.DateKey
I havent included the joins in this query, but they are present

Related

SUM with left outer join gets inflated result

The following query gives me the MRR (monthly recurring revenue) for my customer:
with dims as (
select distinct subscription_id, country_name, product_name from revenue
where site_id = '18XLsHIVSJg' and subscription_id is not null
)
select to_date('2022-07-01') as occurred_date,
count(distinct srm.subscription_id) as subscriptions,
count(distinct srm.receiver_contact) as subscribers,
sum(srm.baseline_mrr) as mrr_srm
from subscription_revenue_mart srm
join dims d on d.subscription_id = srm.subscription_id
where srm.site_id = '18XLsHIVSJg'
-- MRR as of the day before ie June 30th
and to_date(srm.creation_date) < '2022-07-01'
-- Counting the subscriptions active after July 1st
and ((srm.subscription_status = 'SUBL.A') or
-- Counting the subscriptions canceled/deactivated after July 1st
(srm.subscription_status = 'SUBL.C' and (srm.deactivation_date >= '2022-07-01') or (srm.canceled_date >= '2022-07-01')) ) group by 1;
I get a total of $5922.15 but I need to add data from another table to capture upgrades/downgrades a customer makes on a product subscription. Using the same approach as above, I can query my "change" table thusly:
select subscription_id, sum(mrr_change_amount) mrr_change_amount,max(subscription_event_date) subscription_event_date from subscription_revenue_mart_change srmc
where site_id = '18XLsHIVSJg'
and to_date(srmc.creation_date) < '2022-07-01'
and ((srmc.subscription_status = 'SUBL.A')
or (srmc.subscription_status = 'SUBL.C' and (srmc.deactivation_date >= '2022-07-01') or (srmc.canceled_date >= '2022-07-01')))
group by 1;
I get a total of $3635.47
When I combine both queries into one, I get an inflated result:
with dims as (
select distinct subscription_id, country_name, product_name from revenue
where site_id = '18XLsHIVSJg' and subscription_id is not null
),
change as (
select subscription_id, sum(mrr_change_amount) mrr_change_amount,
-- there can be multiple changes per subscription
max(subscription_event_date) subscription_event_date from subscription_revenue_mart_change srmc
where site_id = '18XLsHIVSJg'
and to_date(srmc.creation_date) < '2022-07-01'
and ((srmc.subscription_status = 'SUBL.A')
or (srmc.subscription_status = 'SUBL.C' and (srmc.deactivation_date >= '2022-07-01') or (srmc.canceled_date >= '2022-07-01')))
group by 1
)
select to_date('2022-07-01') as occurred_date,
count(distinct srm.subscription_id) as subscriptions,
count(distinct srm.receiver_contact) as subscribers,
-- See comment RE: LEFT OUTER join
sum(coalesce(c.mrr_change_amount,srm.baseline_mrr)) as mrr
from subscription_revenue_mart srm
join dims d
on d.subscription_id = srm.subscription_id
-- LEFT OUTER join required for customers that never made a change
left outer join change c
on srm.subscription_id = c.subscription_id
where srm.site_id = '18XLsHIVSJg'
and to_date(srm.creation_date) < '2022-07-01'
and ((srm.subscription_status = 'SUBL.A')
or (srm.subscription_status = 'SUBL.C' and (srm.deactivation_date >= '2022-07-01') or (srm.canceled_date >= '2022-07-01'))) group by 1;
It should be $9557.62 ie (5922.15 + $3635.47) but the query outputs $16116.91, which is wrong.
I think the explode-implode syndrome may cause this.
I had designed my "change" CTE to prevent this by aggregating all the relevant fields but it's not working.
Can someone provide pointers on the best way to work around this issue?
It would help if you gave us sample data too, but I see a problem here:
sum(coalesce(c.mrr_change_amount,srm.baseline_mrr)) as mrr
Why COALESCE? That will give you one of the 2 numbers, but I guess what you want is:
sum(ifnull(c.mrr_change_amount, 0) + srm.baseline_mrr) as mrr
That's the best I can offer with what you've given us.

YTD for the below query

I want to add add the Year to date component to this code. I have tried some other ways but I am not getting what I would like to see. Can someone please help me revised this to include the YTD in addition to the Month to date that is already there?
SELECT
COST__DESC,
ST.AD_SRV_MTN AS MONTH_OF_AD,
COUNT(DISTINCT CM.CM_NBR) AS CMS,
MEM_MO AS MBR_MTH,
CMS/MBR_MTH*1000 AS CMS_PER_1000
FROM XTR.FT_CM AS CM
JOIN XTR.FT_ST AS ST ON ST.CM_NBR = CM.CM_NBR
JOIN XTR.DIM_MED_CST AS MC ON ST.CST_CK = MCC.CST_CK
JOIN XTR.DIM_AF AS AFF ON ST.PRO_CK = AFF.AFF_CK
JOIN XTR.DIM_ADJDCTN_STAT AS A_S ON ST.ADJDCTN_STAT_CK = A_S.ADJDCTN_STAT_CK
JOIN XTR.DIM_ADJ_OT AS OT ON ST.ADJ_CK = OT.ADJ_CK
LEFT JOIN
(SELECT
CALENDAR_YEAR_MONTH as YEAR_MO,
SUM(MBR.COUNT_NBR) as MEM_MO
FROM XTR.FT_MBR_MONTHS MBR
INNER JOIN DIM_MBR_C ON MBR.DB_MBR_CK = DIM_MBR_C.DB_MBR_CK
AND MBR.DATE_CK BETWEEN DIM_MBR_C.DB_eff_date_ck
AND DIM_MBR_C.DB_END_DATE_CK
INNER JOIN DIM_DATE DT ON ELI_DATE_CK = DT.DATE_CK
WHERE MBR.F_C_CK = 500058321 AND YEAR_MO >= 201701
GROUP BY 1) MM ON ST.AD_SRV_MTN = MM.YEAR_MO
WHERE ST.F_C_CK = 500058321 AND ST.ST_START_DATE_CK >= 20200101
AND ST.AD_SRV_MTN > 201912 AND MC.MED_DESC IN ('Er', 'IP')
AND ST.AD_SRV_MTN < ((EXTRACT (YEAR FROM CURRENT_DATE) *100) +
EXTRACT (MONTH FROM CURRENT_DATE))
GROUP BY 1,2,4
ORDER BY 1,2
Honestly I don't really get your SQL and what is counted, but: Your can play with dates quite easy in Teradata, as Dates are stored (and can be used) internally as INTEGER. Just keep in mind year 1900 as year 0 and format YYYYMMDD.
So e.g. 16-Apr-2020 is in Format YYYYMMDD 20200416 and if you take 1900 as 0 you'll end up with 1200416 which is the internal format. Just try SELECT CURRENT_DATE (INT); - So if you want compare YearNumers you just have to divide by 10000.
With this your can implement YTD as SUM (CASE WHEN CURRENT_DATE/10000 = <YourDateField>/10000 THEN <YourKPI> else 0 END) as YourKPI_YTD. Counting can be done by SUM...THEN 1 ELSE 0 END....

Summing Two Columns from Two Tables with Two Dates

I work for a CPG company and need to create a report that compares the previous month's delivered units to the next month's forecast. (Simply, our forecasting tool screws up occasionally and this will help identify when the forecast is off.)
My issue is my SQL query is summing forecast sales correctly, but the sum of total delivered is not respecting the dates I have in my WHERE clause -- it's summing total delivered for as far back as the query can reach.
Here is my query:
SELECT
DelUnits.Customer, DelUnits.ObsText01,
FinalFcst.SKU, FinalFcst.Customer,
SUM(DelUnits.Value) AS TotalDelivered,
SUM(FinalFcst.FinalFcst) AS ForecastSales
FROM
DelUnits
LEFT JOIN
FinalFcst ON DelUnits.Customer = FinalFcst.Customer
WHERE
(FinalFcst.DT >= '2018-01-01' and FinalFcst.DT <= '2018-01-31')
AND (DelUnits.Date >= '2017-12-01' and DelUnits.Date <= '2017-12-31')
AND DelUnits.ObsText01 = '10_LB'
AND FinalFcst.SKU = '10_LB'
GROUP BY
DelUnits.Customer, DelUnits.ObsText01, FinalFcst.SKU, FinalFcst.Customer
Again, the query seems to work correctly for the final forecast (summing the forecast between 1/1/18 - 1/31/18) but sums the entire delivery history for a customer. I don't understand why it won't sum the delivery history for just 12/1/17 - 12/31/17.
Thank you for your help!
Presumably, there is only one row for FinalFcst. So, either include it in the GROUP BY clause or use MAX() instead of SUM():
max(FinalFcst.FinalFcst) as ForecastSales
One way to achieve this is to calculate TotalDelivered and ForecastSales in 2 different queries and then join them together.
Try this:
SELECT DelUnits.customer,
DelUnits.obstext01,
FinalFcst.sku,
FinalFcst.customer,
totaldelivered,
forecastsales
FROM (SELECT customer,
obstext01,
Sum(value) AS TotalDelivered
FROM delunits
WHERE date >= '2017-12-01'
AND date <= '2017-12-31'
AND obstext01 = '10_LB'
GROUP BY customer,
obstext01) DelUnits
LEFT JOIN (SELECT customer,
sku,
Sum(finalfcst) AS ForecastSales
FROM finalfcst
WHERE dt >= '2018-01-01'
AND dt <= '2018-01-31'
AND sku = '10_LB'
GROUP BY customer,
sku) FinalFcst ON DelUnits.customer = FinalFcst.customer
You have a many to many relationship between the tables. Ultimately you need to SUM() one table before joining to the other to create a one to many relationship, or you end up duplicating records.
My favorite approach is a derived table:
SELECT C.Customer,
C.ObsText01,
FC.SKU,
C.TotalDelivered,
SUM(FC.FinalFcst) ForecastSales
FROM (SELECT SUM(Value) TotalDelivered, Customer, ObsText01
FROM DelUnits
WHERE Date >= '2017-12-01' AND Date <= '2017-12-31'
AND ObsText01 = '10_LB'
GROUP BY Customer) C
LEFT JOIN FinalFcst FC ON C.Customer = FC.Customer
AND FC.DT >= '2018-01-01'
AND FC.DT <= '2018-01-31'
AND FC.SKU = '10_LB'
GROUP BY C.Customer, C.ObsText01, FC.SKU, C.TotalDelivered
A couple things: Added your forecast table filters to the join predicate, since having those in the WHERE will create an INNER JOIN out of your LEFT JOIN. Also removed FC.Customer from the select and the group since it is redundant with C.Customer.
Maybe you could try to create a temp table to calculate the delivery history. I am not sure of the SQL Server verbiage, but something like this:
WITH DEL_HIST AS
(SELECT DelUnits.Customer,
DelUnits.ObsText01,
sum(DelUnits.Value) as TotalDelivered,
FROM DelUnits
Where(DelUnits.Date >= '2017-12-01' and DelUnits.Date <= '2017-12-31')
and DelUnits.ObsText01 = '10_LB'
Group By DelUnits.Customer, DelUnits.ObsText01)
SELECT
DEL_HIST.Customer,
DEL_HIST.ObsText01,
FinalFcst.SKU,
FinalFcst.Customer,
DEL_HIST.TotalDelivered,
sum(FinalFcst.FinalFcst) as ForecastSales
FROM DEL_HIST
left join FinalFcst ON DelUnits.Customer = FinalFcst.Customer
Where (FinalFcst.DT >= '2018-01-01' and FinalFcst.DT <= '2018-01-31')
and FinalFcst.SKU = '10_LB'
Group By DelUnits.Customer, DelUnits.ObsText01, FinalFcst.SKU, FinalFcst.Customer

Teradata spool space issue on running a sub query with Count

I am using below query to calculate business days between two dates for all the order numbers. Business days are already available in the teradata table Common_WorkingCalendar. But, i'm also facing spool space issue while i execute the query. I have ample space available in my data lab. Need to optimize the query. Appreciate any inputs.
SELECT
tx."OrderNumber",
(SELECT COUNT(1) FROM Common_WorkingCalendar
WHERE CalDate between Cast(tx."TimeStamp" as date) and Cast(mf.ShipDate as date)) as BusDays
from StoreFulfillment ff
inner join StoreTransmission tx
on tx.OrderNumber = ff.OrderNumber
inner join StoreMerchandiseFulfillment mf
on mf.OrderNumber = ff.OrderNumber
This is a very inefficient way to get this count which results in a product join.
The recommended approach is adding a sequential number to your calendar which increases only on business days (calculated using SUM(CASE WHEN businessDay THEN 1 ELSE 0 END) OVER (ORDER BY CalDate ROWS UNBOUNDED PRECEDING)), then it's two joins, for the start date and the end date.
If this calculation is needed a lot you better add a new column, otherwise you can do it on the fly:
WITH cte AS
(
SELECT CalDate,
-- as this table only contains business days you can use this instead
row_number(*) Over (ORDER BY CalDate) AS DayNo
FROM Common_WorkingCalendar
)
SELECT
tx."OrderNumber",
to_dt.DayNo - from_dt.DayNo AS BusDays
FROM StoreFulfillment ff
INNER JOIN StoreTransmission tx
ON tx.OrderNumber = ff.OrderNumber
INNER JOIN StoreMerchandiseFulfillment mf
ON mf.OrderNumber = ff.OrderNumber
JOIN cte AS from_dt
ON from_dt.CalDate = Cast(tx."TimeStamp" AS DATE)
JOIN cte AS to_dt
ON to_dt.CalDate = Cast(mf.ShipDate AS DATE)

query to generate transactions from previous month

I need to write a query which when executed at the beginning of the current month must generate a report which contains total transactions made in the previous month and I have written the below query:
SELECT
l.state AS Province
,l.taxing_entity AS TaxJurisdiction
,COUNT(DISTINCT t.trans_id) AS TotalTransCount
FROM TRANSACTION AS t
LEFT OUTER JOIN location AS l
ON t.location_id = l.location_id
LEFT OUTER JOIN trans_line AS tl
ON t.trans_id = tl.trans_id
LEFT OUTER JOIN contract as c
ON t.contract_id = c.contract_id
WHERE
l.chain_id = 10
AND c.issuer_id IN (156967)
AND t.extra_5 BETWEEN LAST_DAY(TODAY - 2 units month) + 1 units day AND LAST_DAY(TODAY - 1 units month)
AND tl.cat NOT IN ('DEF','DEFD','DEFC')
GROUP BY l.state, l.taxing_entity, Province
ORDER BY l.state,l.taxing_entity
But this query throws an error "It is not possible to convert between the specified types. ". I tried changing the date range as below:
t.extra_5 >= DATEADD(MONTH, DATEDIFF(MONTH, 31, CURRENT_TIMESTAMP), 0) AND t.extra_5 < DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP), 0)
and
t.extra_5 > DateAdd(WEEK, -1, GETDATE()+1) and t.extra_5<=GETDATE()
But nothing has worked out so far. The current format for the column "extra_5" is as below:
Can someone please suggest a way to get the total transactions from previous month.