Sql Sales Report - sql

I am trying to make a report for sales. This is what I have so far but I need to break it down into stores. There is a field in the orders table for storeid. I would like to return the totals for each store. Can anyone point me in the right direction for this?
select DAY(d.date) as Day, MONTH(d.date) as Month, YEAR(d.date) as year, isnull(t.amnt, 0) as [Total Sales] from (
SELECT
sum(o.OrderTotal) amnt,
DAY(o.OrderDate) as 'Day',
YEAR(o.OrderDate) as 'Year',
MONTH(o.OrderDate) as 'Month'
FROM [Orders] o
where
o.OrderDate > #StartDate + ' 00:00:00' and o.OrderDate < '' + #EndDate + ' 23:59:59'
group by YEAR(o.OrderDate), Month(o.OrderDate), DAY(o.OrderDate)
) t
right join (
select dateadd(dd, -number, getdate()) as date
from master.dbo.spt_values
where type = 'p' and number < DATEDIFF(d, #StartDate, #EndDate) +1
) d on year(d.date) = t.[year] and month(d.date) = t.[month] and day(d.date) = t.[day]
order by YEAR(d.date), MONTH(d.date), DAY(d.date)

Add storeId to the GROUP BY clause and SELECT clause.
select DAY(d.date) as Day, MONTH(d.date) as Month, YEAR(d.date) as year, isnull(t.amnt, 0) as [Total Sales], o.storeId from (
SELECT
sum(o.OrderTotal) amnt,
DAY(o.OrderDate) as 'Day',
YEAR(o.OrderDate) as 'Year',
MONTH(o.OrderDate) as 'Month'
FROM [Orders] o
where
o.OrderDate > #StartDate + ' 00:00:00' and o.OrderDate < '' + #EndDate + ' 23:59:59'
group by YEAR(o.OrderDate), Month(o.OrderDate), DAY(o.OrderDate), o.storeId
) t
right join (
select dateadd(dd, -number, getdate()) as date
from master.dbo.spt_values
where type = 'p' and number < DATEDIFF(d, #StartDate, #EndDate) +1
) d on year(d.date) = t.[year] and month(d.date) = t.[month] and day(d.date) = t.[day]
order by YEAR(d.date), MONTH(d.date), DAY(d.date)

Related

How Can I write in my code to exclude accounts that have had a payment posted w/in last 45 days?

I'm working in SQL Server Mgmt Studio and I'm trying to identify accounts that have not had a payment posted since the last 45 days. I've tried declaring a min and max date with getdate being less than 45 days, but that didnt work. I've also tried stating "where last payment !> getdate() -45".... but this did not give me the results I was looking for. what I need the query to do is only identify accounts that truly have not had a payment post in the last 45 days. but I'm not sure how to state this in my where clause. Here's my query
DECLARE #minDate datetime;
DECLARE #maxDate datetime;
SET #minDate = GETDATE();
SET #maxDate = GETDATE() - 45;
SELECT DISTINCT
a.id,
a.FacilityCode AS [Facility],
a.accountUnit,
a.accountNum AS [Account Number],
a.amountBalance AS [Balance],
a.accountstatus AS [Status],
CONVERT(date, a.accountStatusDate) AS StatusDate,
pmtEntryDate AS [Pmt Entry Date],
v.LastLinkARpmtDate AS [Last Pmt Date],
CONVERT(date, a.accountnextactdate) AS NextActionDate,
CONVERT(date, a.rpcDate) AS RightpartyContactDate,
a.flag AS accountFlag,
pay.flag AS pmtFlag,
a.accounttype
FROM dbo.tbAccount a
JOIN dbo.tbpmtinfo pay ON a.id = pay.id
JOIN dbo.vLastPmtDate v ON v.id = a.id
FULL JOIN (SELECT id,
MAX(deDate) AS MFSLoadDate
FROM dbo.tbDataEvents (NOLOCK)
WHERE deNewVal = 'MFS'
GROUP BY id) m ON m.id = a.id
WHERE pay.flag IN ('D')
AND a.amountBalance > 0
AND a.FacilityCode IN ('PHKY', 'QANM', 'QAOH', 'QBCA', 'QBIL', 'QBTX', 'QCIL', 'QDAL', 'QEWY', 'QFAR', 'QFGA',
'QGIL', 'QHAR', 'QHIL', 'QHTN', 'QLAL', 'QLPA', 'QMIL', 'QMNC', 'QMNM', 'QMNV', 'QMOR',
'QMTN', 'QMTX', 'QMUT', 'QRIL', 'QRKY', 'QSPA', 'QTGA', 'QTKY', 'QUIL', 'QVIL', 'QWIL', 'LHFL')
AND a.amountBalance >= '1000'
AND a.accountStatus IN ('PA', 'PP', 'BPA')
AND a.flag = 'A'
AND a.accountType IN ('Resid', 'Slfpy')
--and LastLinkARpmtDate !> Getdate() -45 and accountNum = '40728597'
AND LastLinkARpmtDate BETWEEN #minDate AND #maxDate;
I would use a WHERE NOT EXISTS clause to eliminate recent activity:
SELECT DISTINCT a.id
,a.FacilityCode [Facility]
,a.accountUnit
,a.accountNum [Account Number]
,a.amountBalance [Balance]
,a.accountstatus [Status]
,convert(DATE, a.accountStatusDate) StatusDate
,pmtEntryDate [Pmt Entry Date]
,v.LastLinkARpmtDate [Last Pmt Date]
,convert(DATE, a.accountnextactdate) NextActionDate
,convert(DATE, a.rpcDate) RightpartyContactDate
,a.flag AS accountFlag
,pay.flag AS pmtFlag
,a.accounttype
FROM dbo.tbAccount AS a
JOIN dbo.tbpmtinfo AS pay ON a.id = pay.id
JOIN dbo.vLastPmtDate AS v ON v.id = a.id
FULL JOIN (
SELECT id
,Max(deDate) AS MFSLoadDate
FROM dbo.tbDataEvents(NOLOCK)
WHERE deNewVal = 'MFS'
GROUP BY id
) m ON m.id = a.id
WHERE pay.flag IN ('D')
AND a.amountBalance > 0
AND a.FacilityCode IN (
'PHKY'
,'QANM'
,'QAOH'
,'QBCA'
,'QBIL'
,'QBTX'
,'QCIL'
,'QDAL'
,'QEWY'
,'QFAR'
,'QFGA'
,'QGIL'
,'QHAR'
,'QHIL'
,'QHTN'
,'QLAL'
,'QLPA'
,'QMIL'
,'QMNC'
,'QMNM'
,'QMNV'
,'QMOR'
,'QMTN'
,'QMTX'
,'QMUT'
,'QRIL'
,'QRKY'
,'QSPA'
,'QTGA'
,'QTKY'
,'QUIL'
,'QVIL'
,'QWIL'
,'LHFL'
)
AND a.amountBalance >= '1000'
AND a.accountStatus IN (
'PA'
,'PP'
,'BPA'
)
AND a.flag = 'A'
AND a.accountType IN (
'Resid'
,'Slfpy'
)
AND NOT EXISTS (
SELECT NULL
FROM vLastPmtDate
WHERE v.id = a.id
AND CAST(v.LastLinkARpmtDate AS DATE) > CAST(dateadd(day, - 45, getdate() AS DATE))
)
AND accountNum = '40728597'
AND LastLinkARpmtDate BETWEEN #minDate
AND #maxDate;
The function dateadd() is what you need:
DATEADD (datepart , number , date)
Set #maxDate = DATEADD(DAY, -45, GETDATE());

GROUP BY & SUM of values with missing MONTHS

I have gone through a lot of examples and joined couple of them in order to come down to the following statement;
DECLARE #StartDate SMALLDATETIME, #EndDate SMALLDATETIME;
SELECT #StartDate = '20170930', #EndDate = '20180930';
;WITH d(d) AS
(
SELECT DATEADD(MONTH, n, DATEADD(MONTH, DATEDIFF(MONTH, 0, #StartDate), 0))
FROM ( SELECT TOP (DATEDIFF(MONTH, #StartDate, #EndDate) + 1)
n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1
FROM sys.all_objects ORDER BY [object_id] ) AS n
)
SELECT
[Period] = CONVERT(VARCHAR(4), YEAR(d.d)) + '-' + CONVERT(VARCHAR(2), MONTH(d.d)),
QtyTotal = ISNULL(SUM(o.QEXIT),0)
FROM d LEFT OUTER JOIN VE_STOCKTRANS AS o
ON o.TRANSDATE >= d.d
AND o.TRANSDATE < DATEADD(MONTH, 1, d.d)
WHERE STOCKID = 6000 AND TRANSTYPE = 3553
GROUP BY d.d
ORDER BY d.d;
I need to get the total sales quaantity of an item for the past year. If the item does not have any sales for that particular month, 0 should be displayed next to that month. The above query does what is required unless the WHERE clause is provided. As soon as I add the WHERE clause to get the data for a specific product, the months with no sales dissappears.
I would be grateful if an experienced SQL developer can show me the right direction on this.
Thanks
You need to move condtition to ON:
-- ...
SELECT
[Period] = CONVERT(VARCHAR(4),YEAR(d.d)) +'-'+ CONVERT(VARCHAR(2), MONTH(d.d)),
QtyTotal = ISNULL(SUM(o.QEXIT),0)
FROM d LEFT OUTER JOIN VE_STOCKTRANS AS o
ON o.TRANSDATE >= d.d
AND o.TRANSDATE < DATEADD(MONTH, 1, d.d)
AND STOCKID = 6000 AND TRANSTYPE = 3553 -- here
GROUP BY d.d
ORDER BY d.d;
A more generic approach is to apply the filter before you join.
;WITH d(d) AS
(
SELECT DATEADD(MONTH, n, DATEADD(MONTH, DATEDIFF(MONTH, 0, #StartDate), 0))
FROM ( SELECT TOP (DATEDIFF(MONTH, #StartDate, #EndDate) + 1)
n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1
FROM sys.all_objects ORDER BY [object_id] ) AS n
),
o AS
(
SELECT *
FROM VE_STOCKTRANS
WHERE STOCKID = 6000
AND TRANSTYPE = 3553
)
SELECT
[Period] = CONVERT(VARCHAR(4), YEAR(d.d)) + '-' + CONVERT(VARCHAR(2), MONTH(d.d)),
QtyTotal = ISNULL(SUM(o.QEXIT),0)
FROM
d
LEFT OUTER JOIN
o
ON o.TRANSDATE >= d.d
AND o.TRANSDATE < DATEADD(MONTH, 1, d.d)
GROUP BY
d.d
ORDER BY
d.d;
It's not strictly necessary here, as you've seen in the other answer. When doing FULL OUTER JOIN or other complex queries, however, it can be extremely helpful to filter your sources in one scope and join in a separate scope.
(I always filter my sources, I hate lumpy ketchup.)

Display Month Gaps for Each location

I have the following query which takes in the opps and calculates the duration, and revenue for each month. However, for some locations, where there is no data, it is missing some months. Essentially, I would like all months to appear for each of the location and record type. I tried a left outer join on the calendar but that didn't seem to work either.
Here is the query:
;With DateSequence( [Date] ) as
(
Select CAST(#fromdate as DATE) as [Date]
union all
Select CAST(dateadd(day, 1, [Date]) as Date)
from DateSequence
where Date < #todate
)
INSERT INTO CalendarTemp (Date, Day, DayOfWeek, DayOfYear, WeekOfYear, Month, MonthName, Year)
Select
[Date] as [Date],
DATEPART(DAY,[Date]) as [Day],
DATENAME(dw, [Date]) as [DayOfWeek],
DATEPART(DAYOFYEAR,[Date]) as [DayOfYear],
DATEPART(WEEK,[Date]) as [WeekOfYear],
DATEPART(MONTH,[Date]) as [Month],
DATENAME(MONTH,[Date]) as [MonthName],
DATEPART(YEAR,[Date]) as [Year]
from DateSequence option (MaxRecursion 10000)
;
DELETE FROM CalendarTemp WHERE DayOfWeek IN ('Saturday', 'Sunday');
SELECT
AccountId
,AccountName
,Office
,Stage = (CASE WHEN StageName = 'Closed Won' THEN 'Closed Won'
ELSE 'Open'
END)
,Id
,Name
,RecordType= (CASE
WHEN recordtypeid = 'LAS1' THEN 'S'
END)
,Start_Date
,End_Date
,Probability
,Estimated_Revenue_Won = ISNULL(Amount, 0)
,ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Name) AS Row
--,Revenue_Per_Day = CAST(ISNULL(Amount/NULLIF(dbo.CalculateNumberOFWorkDays(Start_Date, End_Date),0),0) as money)
,YEAR(c.Date) as year
,MONTH(c.Date) as Month
,c.MonthName
--, ISNULL(CAST(Sum((Amount)/NULLIF(dbo.CalculateNumberOFWorkDays(Start_Date, End_Date),0)) as money),0) As RevenuePerMonth
FROM SF_Extracted_Opps o
LEFT OUTER JOIN CalendarTemp c on o.Start_Date <= c.Date AND o.End_Date >= c.Date
WHERE
Start_Date <= #todate AND End_Date >= #fromdate
AND Office IN (#Location)
AND recordtypeid IN ('LAS1')
GROUP BY
AccountId
,AccountName
,Office
,(CASE WHEN StageName = 'Closed Won' THEN 'Closed Won'
ELSE 'Open'
END)
,Id
,Name
,(CASE
WHEN recordtypeid = 'LAS1' THEN 'S'
END)
,Amount
--, CAST(ISNULL(Amount/NULLIF(dbo.CalculateNumberOFWorkDays(Start_Date, End_Date),0),0) as money)
,Start_Date
,End_Date
,Probability
,YEAR(c.Date)
,Month(c.Date)
,c.MonthName
,dbo.CalculateNumberOFWorkDays(Start_Date, End_Date)
ORDER BY Office
, (CASE
WHEN recordtypeid = 'LAS1' THEN 'S'
END)
,(CASE WHEN StageName = 'Closed Won' THEN 'Closed Won'
ELSE 'Open'
END)
, [Start_Date], Month(c.Date), AccountName, Row;
I tried adding another left outer join to this and using this a sub query and the join essentially on the calendar based on the year and month, but that did not seem to work either. Suggestions would be extremely appreciated.
--Date Calendar for each location:
;With DateSequence( [Date], Locatio) as
(
Select CAST(#fromdate as DATE) as [Date], oo.Office as location
union all
Select CAST(dateadd(day, 1, [Date]) as Date), oo.Office as location
from DateSequence dts
join Opportunity_offices oo on 1 = 1
where Date < #todate
)
--select result
INSERT INTO CalendarTemp (Location,Date, Day, DayOfWeek, DayOfYear, WeekOfYear, Month, MonthName, Year)
Select
location,
[Date] as [Date],
DATEPART(DAY,[Date]) as [Day],
DATENAME(dw, [Date]) as [DayOfWeek],
DATEPART(DAYOFYEAR,[Date]) as [DayOfYear],
DATEPART(WEEK,[Date]) as [WeekOfYear],
DATEPART(MONTH,[Date]) as [Month],
DATENAME(MONTH,[Date]) as [MonthName],
DATEPART(YEAR,[Date]) as [Year]
from DateSequence option (MaxRecursion 10000)
;
you have your LEFT JOIN backwards if you want all records from CalendarTemp and only those that match from SF_Extracted_Opps then you the CalendarTemp should be the table on the LEFT. You can however switch LEFT JOIN to RIGHT JOIN and it should be fixed. The other issue will be your WHERE statement is using columns from your SF_Extracted_Opps table which will just make that an INNER JOIN again.
here is one way to fix.
SELECT
.....
FROM
CalendarTemp c
LEFT JOIN SF_Extracted_Opps o
ON o.Start_Date <= c.Date AND o.End_Date >= c.Date
AND o.Start_Date <= #todate AND End_Date >= #fromdate
AND o.Office IN (#Location)
AND o.recordtypeid IN ('LAS1')
The other issue you might run into is because you remove weekends from your CalendarTemp Table not all dates are represented I would test with the weekends still in and out and see if you get different results.
this line:
AND o.Start_Date <= #todate AND End_Date >= #fromdate
should not be needed either because you are already limiting the dates from the line before and values in your CalendarTempTable
A note about your CalendarDate table you don't have to go back and delete those records simply add the day of week as a WHERE statement on the select that populates that table.
Edit for All Offices you can use a cross join of your offices table with your CalendarTemp table to do this do it in your final query not the cte that builds the calendar. The problem with doing it in the CTE calendar definition is that it is recursive so you would have to do it in both the anchor and the recursive member definition.
SELECT
.....
FROM
CalendarTemp c
CROSS JOIN Opportunity_offices oo
LEFT JOIN SF_Extracted_Opps o
ON o.Start_Date <= c.Date AND o.End_Date >= c.Date
AND o.Start_Date <= #todate AND End_Date >= #fromdate
AND oo.office = o.Office
AND o.recordtypeid IN ('LAS1')

Handling Null value

I am trying to generate data per sales people per week while comparing my results with last week and subtracting last week from current week. Sometimes current week doesn't have any value. I would like to handle that situation by replacing it by '0'. I am not really good at this so I am seeking help.
SELECT t2.emp_name,
t2.pipelinetarget,
Sum(t0.maxsumloc) AS SaleOpp,
Datepart(ww, t0.opendate) AS [Week #],
Isnull ((SELECT Sum(maxsumloc) AS Expr1
FROM dbo.oopr AS A
WHERE ( slpcode = t1.slpcode )
AND ( Datepart(ww, opendate) =
Datepart(ww, Getdate()) - 1 )
AND ( Datepart(yy, opendate) = Datepart(yy, Getdate()) )
GROUP BY slpcode), 0) AS LastWeek,
Isnull ((SELECT Sum(maxsumloc) AS Expr1
FROM dbo.oopr AS A
WHERE ( Datepart(ww, opendate) = Datepart(ww, Getdate()) )
AND ( Datepart(yy, opendate) = Datepart(yy, Getdate()) )
AND ( maxsumloc >= 10000.00 )
AND ( slpcode = t1.slpcode )
GROUP BY slpcode), 0) AS [SumOf-Opp-obove-10k],
Isnull ((SELECT Count(opprid) AS Expr1
FROM dbo.oopr AS A
WHERE ( Datepart(ww, opendate) = Datepart(ww, Getdate()) )
AND ( Datepart(yy, opendate) = Datepart(yy, Getdate()) )
AND ( maxsumloc >= 10000.00 )
AND ( slpcode = t1.slpcode )
GROUP BY slpcode), 0) AS [#-Opp-obove-10k],
Isnull ((SELECT Sum(maxsumloc) AS Expr1
FROM dbo.oopr AS A
WHERE ( Datepart(ww, opendate) = Datepart(ww, Getdate()) )
AND ( Datepart(yy, opendate) = Datepart(yy, Getdate()) )
AND ( maxsumloc < 10000.00 )
AND ( slpcode = t1.slpcode )
GROUP BY slpcode), 0) AS [SumOf-Opp-below-10k],
Isnull ((SELECT Count(opprid) AS Expr1
FROM dbo.oopr AS A
WHERE ( Datepart(ww, opendate) = Datepart(ww, Getdate()) )
AND ( Datepart(yy, opendate) = Datepart(yy, Getdate()) )
AND ( maxsumloc < 10000.00 )
AND ( slpcode = t1.slpcode )
GROUP BY slpcode), 0) AS [#-Opp-below-10k]
FROM dbo.oslp AS t1
LEFT OUTER JOIN dbo.oopr AS t0
ON t1.slpcode = t0.slpcode
LEFT OUTER JOIN dbo.[user_qsalestarget(salesrep)] AS t2
ON t2.emp_name = t1.slpname
LEFT OUTER JOIN dbo.ocrd AS t4
ON t4.cardcode = t0.cardcode
LEFT OUTER JOIN dbo.[user_clusters(sp)] AS t5
ON t5.emp_name = t1.slpname
WHERE ( Datepart(ww, t0.opendate) = Datepart(ww, Getdate()) )
AND ( Datepart(yy, t0.opendate) = Datepart(yy, Getdate()) )
AND ( t5.title = 'Outside Sales Rep' )
GROUP BY t2.emp_name,
t1.slpcode,
Datepart(ww, t0.opendate),
t2.pipelinetarget
Look at the coalesce function eg "SELECT COALESCE(thePossibleNullValue, 0) FROM mytable" which returns the first non-null value ie either your value or zero if it's null in this example

Group dates by week?

I'm trying to group a series of dates by week. So far I have the following:
SELECT DATEPART(week, CONVERT(VARCHAR(50), e.event_date, 107)) AS 'Date' ,
c.setting_secondary AS 'Workflow Cat' ,
d.setting_main AS 'Error Type' ,
SUM(e.event_count) AS 'Total'
FROM marlin.support_events AS e
INNER JOIN marlin.support_config AS c
ON e.event_category = c.setting_code
AND config_code = 60
INNER JOIN marlin.support_config AS d
ON e.event_type = d.setting_code
AND d.config_code = 70
WHERE e.event_date BETWEEN DATEADD(MONTH, -2, GETDATE()) AND GETDATE()
AND c.setting_secondary = 'Expenditure Voucher'
AND d.setting_main IN ( 'Unstarted' , 'Timeout' )
GROUP BY
DATEPART(week, CONVERT(VARCHAR(50), e.event_date, 107)) ,
c.setting_secondary ,
d.setting_main ,
e.event_summary
This shows me the week number but not the date that week started within, like so:
How can I show what date this week begins with?
Answer:
Answer identified below and an alternate method I also found for doing this:
DATEADD(dd, -(DATEPART(dw, e.event_date)-1), e.event_date)
You can get the year part from the date, append the first day of first month and then add the (#week - 1) to get the starting day of the week the event_date belongs to, as follows:
SELECT EventDate, WorkflowCat, ErrorType, SUM(EventCount) AS 'Total'
FROM
(
SELECT DATEADD(ww,
DATEPART(ww, e.event_date) - 1,
CONVERT(DATETIME,
CONVERT(VARCHAR(4), DATEPART(yy, e.event_date)) + '-01-01')) AS 'EventDate' ,
c.setting_secondary AS 'WorkflowCat' ,
d.setting_main AS 'ErrorType',
e.event_summary as 'EventSummary'
e.event_count AS 'EventCount'
FROM marlin.support_events AS e
INNER JOIN marlin.support_config AS c
ON e.event_category = c.setting_code
AND config_code = 60
INNER JOIN marlin.support_config AS d
ON e.event_type = d.setting_code
AND d.config_code = 70
WHERE e.event_date BETWEEN DATEADD(MONTH, -2, GETDATE()) AND GETDATE()
AND c.setting_secondary = 'Expenditure Voucher'
AND d.setting_main IN ( 'Unstarted' , 'Timeout' )
)
GROUP BY EventDate, WorkflowCat, ErrorType, EventSummary