I have a query which I eventually got to work fine but what I really need is the results to be displayed using the SQL PRINT command. The reason for this is I am automating the results to be emailed, and if I can have them come out as printed text then I can just embed the results in the email using the tool we use here. Otherwise, the current results have to be attached as a file and I would prefer the printed text if possible.
I have tried to modify the query by adding DECLARE and PRINT but I am really confused and can't figure it out. The query has 2 CTE's in it pulling data from multiple databases. What it is doing is selecting all the sale numbers/ID's from our SAP system for yesterday and comparing them with our the Sale numbers/ID's from our POS system for yesterday to make sure every sale in our POS system is now in SAP. The query itself works fine.
How can I print the results of this query?
WITH CTE1 (SAP_SALE)
AS
(
select distinct convert(BIGINT,convert(varchar(15),WERKS)+(select RIGHT(convert(Varchar(20),BONNR),7)))
as Branch_tx_no from [PDP].[pdp].[S120] WITH (NOLOCK)
where SPTAG >= CAST(CONVERT(VARCHAR(10), GETDATE() -1, 101) AS DATETIME) AND
SPTAG < CAST(CONVERT(VARCHAR(10), GETDATE(), 101) AS DATETIME)
),
CTE2 (AR_SALE)
AS
(
select convert(varchar(15),branch_no)+convert(varchar(15),sale_tx_no)
from [ARDB01].[PP_BODATA].[DBO].[sales_tx_hdr] WITH (NOLOCK)
WHERE sale_date >= CAST(CONVERT(VARCHAR(10), GETDATE() -1, 101) AS DATETIME) AND
sale_date < CAST(CONVERT(VARCHAR(10), GETDATE(), 101) AS DATETIME)
and sale_type in ('C','L')
)
SELECT AR_SALE FROM CTE2 AS CTE2
Left OUTER JOIN CTE1 AS CTE1
ON CTE1.SAP_SALE = CTE2.AR_SALE
WHERE CTE1.SAP_SALE IS NULL
ORDER BY CTE2.AR_SALE
The easiest solution is to use a cursor and PRINT one row at a time. Or you could use XML-concatenation, if you do not have any special characters in the result:
DECLARE #txt NVARCHAR(MAX);
WITH CTE1 (SAP_SALE)
AS
(
select distinct convert(BIGINT,convert(varchar(15),WERKS)+(select RIGHT(convert(Varchar(20),BONNR),7)))
as Branch_tx_no from [PDP].[pdp].[S120] WITH (NOLOCK)
where SPTAG >= CAST(CONVERT(VARCHAR(10), GETDATE() -1, 101) AS DATETIME) AND
SPTAG < CAST(CONVERT(VARCHAR(10), GETDATE(), 101) AS DATETIME)
),
CTE2 (AR_SALE)
AS
(
select convert(varchar(15),branch_no)+convert(varchar(15),sale_tx_no)
from [ARDB01].[PP_BODATA].[DBO].[sales_tx_hdr] WITH (NOLOCK)
WHERE sale_date >= CAST(CONVERT(VARCHAR(10), GETDATE() -1, 101) AS DATETIME) AND
sale_date < CAST(CONVERT(VARCHAR(10), GETDATE(), 101) AS DATETIME)
and sale_type in ('C','L')
)
SELECT #txt = (
SELECT CHAR(13)+CHAR(10)+AR_SALE FROM CTE2 AS CTE2
Left OUTER JOIN CTE1 AS CTE1
ON CTE1.SAP_SALE = CTE2.AR_SALE
WHERE CTE1.SAP_SALE IS NULL
ORDER BY CTE2.AR_SALE
FOR XML PATH(''),TYPE
).value('.','NVARCHAR(MAX)');
PRINT #txt;
If you need to use PRINT you can combine results of your query into a comma (or other char) separated VARCHAR variable and then print that variable, e.g.
DECLARE #sTMP varchar(1000)
SET #sTMP = ''
-- Your CTE....
SELECT #sTMP = #sTMP + AR_SALE + ',' FROM CTE2 AS CTE2
Left OUTER JOIN CTE1 AS CTE1
ON CTE1.SAP_SALE = CTE2.AR_SALE
WHERE CTE1.SAP_SALE IS NULL
ORDER BY CTE2.AR_SALE
PRINT #sTMP
WITH CTE1 (SAP_SALE)
AS
(
select distinct convert(BIGINT,convert(varchar(15),WERKS)+(select RIGHT(convert(Varchar(20),BONNR),7)))
as Branch_tx_no from [PDP].[pdp].[S120] WITH (NOLOCK)
where SPTAG >= CAST(CONVERT(VARCHAR(10), GETDATE() -1, 101) AS DATETIME) AND
SPTAG < CAST(CONVERT(VARCHAR(10), GETDATE(), 101) AS DATETIME)
),
CTE2 (AR_SALE)
AS
(
select convert(varchar(15),branch_no)+convert(varchar(15),sale_tx_no)
from [ARDB01].[PP_BODATA].[DBO].[sales_tx_hdr] WITH (NOLOCK)
WHERE sale_date >= CAST(CONVERT(VARCHAR(10), GETDATE() -1, 101) AS DATETIME) AND
sale_date < CAST(CONVERT(VARCHAR(10), GETDATE(), 101) AS DATETIME)
and sale_type in ('C','L')
)
SELECT AR_SALE, row_number() over (order by AR_SALE) as r
into #temp -- added this row right here
FROM CTE2 AS CTE2
Left OUTER JOIN CTE1 AS CTE1
ON CTE1.SAP_SALE = CTE2.AR_SALE
WHERE CTE1.SAP_SALE IS NULL
ORDER BY CTE2.AR_SALE
then...
declare #x varchar(100)
declare #i int
set #i = 1
while (#i <= (select max(r) from #temp)) begin
select #x=AR_SALE from #temp where r=#i
print #x
set #i=#i+1
end
Related
With CTE if i assign the variable outside and call the varibale inside the table not accepting the variable but if i pass the value directly inside the CTE query return the value.
DECLARE #dates datetime = '8/5/2019 12:41:55 PM',
#Staff nvarchar(250) = N'staff1';
WITH
CTE AS
(SELECT DI.SchedulerID,
DI.CustID,
ORC.CustomerName,
(SELECT CONVERT(char(5), DI.InTime, 108) AS [time]) AS InTime,
DI.Identifier,
DI.PictureUploaded,
(SELECT CONVERT(char(5), DO.OutTime, 108) AS [time]) AS OutTime,
CONCAT((DATEDIFF(MINUTE, DI.InTime, DO.OutTime) / 60), ':', (DATEDIFF(MINUTE, DI.InTime, DO.OutTime) % 60)) AS SpendInMinutes,
ROW_NUMBER() OVER (PARTITION BY DI.SchedulerID,
ORC.CustomerName
ORDER BY DI.SchedulerID DESC) AS RN
FROM [ServiceUsers].[dbo].[DeliveryIn] DI
INNER JOIN [Distribution].dbo.ORCustomerList ORC ON DI.CustID = ORC.CustID
INNER JOIN [ServiceUsers].[dbo].[DeliveryOut] DO ON DI.SchedulerID = DO.SchedulerID
WHERE (SELECT CONVERT(date, DI.InDate)) = (SELECT #dates)
AND DI.CreatedBy = (SELECT #Staff))
SELECT *
FROM CTE
WHERE RN = 1;
If i pass the values directly to the where it will return the rows.
Note to commenters -- I'm not saying the code is "wrong" and would not run, just that it is strange and not the typical way it would be written
your sql is strange
Where (SELECT CONVERT(date, DI.InDate))=(Select #dates) AND DI.CreatedBy=(Select #Staff)
should be
Where CONVERT(date, DI.InDate)=#dates AND DI.CreatedBy=#Staff
also I would write declare like this
DECLARE #dates datetime;
DECLARE #staff nvarchar(250);
SET #dates='2019-08-05';
SET #Staff=N'staff1';
I've got a recursive cte working to generate a list of dates between #startDate and #endDate, incrementing by quarters.
declare #startDate datetime
declare #endDate datetime
set #startDate= '01-jan-2014'
set #endDate= '01-jul-2017'
;With cte
As
( Select #startDate date1
Union All
Select DateAdd(Month,3,date1) From cte where date1 < #endDate
) select cast(cast( Year(date1)*10000 + MONTH(date1)*100 + 1 as
varchar(255)) as date) quarterlyDates From cte
This yields:
quarterlyDates
--------------
2014-01-01
2014-04-01
2014-07-01
2014-10-01 ...
I'd like to concatenate the output of the cte into a single string as follows:
"'01-jan-2014', '01-apr-2014, '01-jul-2014'..."
etc. I'm baffled by this last step - any help would be greatly appreciated!
Not sure why you want to... but just wrap that bottom cte and use stuff.
declare #table table(quarterlyDates date)
insert into #table
values
('2014-01-01'),
('2014-04-01'),
('2014-07-01'),
('2014-10-01')
SELECT stuff((
SELECT ', ' + cast(quarterlyDates as varchar(max))
FROM #table
FOR XML PATH('')
), 1, 2, '')
And in your code... though the second CTE isn't necessary I leave it for clarity.
declare #startDate datetime
declare #endDate datetime
set #startDate= '01-jan-2014'
set #endDate= '01-jul-2017'
;With cte
As
( Select #startDate date1
Union All
Select DateAdd(Month,3,date1) From cte where date1 < #endDate
),
cte2 as(
select cast(cast( Year(date1)*10000 + MONTH(date1)*100 + 1 as
varchar(255)) as date) quarterlyDates From cte)
SELECT stuff((
SELECT ', ' + cast(quarterlyDates as varchar(max))
FROM cte2
FOR XML PATH('')
), 1, 2, '');
use FOR XML Path with type directive to avoid encoding of illegal characters in result
;WITH cte
AS (SELECT #startDate date1
UNION ALL
SELECT Dateadd(month, 3, date1)
FROM cte
WHERE date1 < #endDate)
SELECT Stuff((SELECT ',' + CONVERT(VARCHAR(15), date1, 106) quarterlyDates
FROM cte
FOR xml path, type).value('.[1]', 'nvarchar(max)'), 1, 1, '');
Note : I have altered the unwanted manipulating in the final select. Use style 106 in Convert function to get the required output format
Late answer and just for fun.
Example
declare #startDate datetime = '01-jan-2014'
declare #endDate datetime = '01-jul-2017'
;With cte
As
( Select date1 = #startDate
,dates = ''''+convert(varchar(max),convert(varchar(11),#startDate,113))+''''
Union All
Select DateAdd(Month,3,date1)
,cte.dates+','''+convert(varchar(11),DateAdd(Month,3,date1) ,106)+''''
From cte where date1 < #endDate
)
Select Top 1 with ties
Dates=lower(replace(Dates,' ','-') )
From cte
Order By Date1 Desc
Returns
'01-jan-2014','01-apr-2014','01-jul-2014','01-oct-2014','01-jan-2015','01-apr-2015','01-jul-2015','01-oct-2015','01-jan-2016','01-apr-2016','01-jul-2016','01-oct-2016','01-jan-2017','01-apr-2017','01-jul-2017'
I want to create a graph for my dataset for the last 24 hours.
I found a solution that works but this is pretty bad since the table I am outer joining cotains every single row in the DB since I am using the (now deprecated) "all" parameter in the group by.
Here is the solution that currently kind of works.
First I declare the date intervals that is 24 hours back in time from now. I declare it twice so I can use it later in the procedure aswell.
Declare #StartDate datetime = dateadd(hour, -24, getdate())
Declare #StartDateProc datetime = dateadd(hour, -24, getdate())
Declare #EndDate datetime = getdate()
I populate the dates into a temp table including a special formated datetsring.
create table #tempTable
(
Date datetime,
DateString varchar(11)
)
while #StartDate <= #EndDate
begin
insert into #tempTable (Date, DateString)
values (#StartDate, convert(varchar(8), #StartDate, 5) + '-' + convert(varchar(2), #StartDate, 108));
SET #StartDate = dateadd(hour,1, #StartDate);
end
This gives me data that looks like this:
Date DateString
---------------------------------------------
2015-12-09 13:59:01.970 09-12-15-13
2015-12-09 14:59:01.970 09-12-15-14
2015-12-09 15:59:01.970 09-12-15-15
2015-12-09 16:59:01.970 09-12-15-16
So what I want is to join my dataset on the matching date string and show the date even if the matching rows is zero.
Here is the rest of the query
select
Date = c.Date,
Amount = sum(c.Amount)
from
DbTable a
outer apply
(select
Date = b.DateString,
Amount = count(*)
from
#tempTable b
where
convert(varchar(8), a.DateColumn, 5) + '-' + convert(varchar(2), a.DateColumn, 108) = b.DateString
group by all
b.DateString) c
where
a.SomeParameter = 'test' and
a.DateColumn >= #StartDateProc and
a.DateColumn <= #EndDate
group by
c.Date
drop table #tempTable
Test to show actual data:
Declare #StartDate datetime = dateadd(hour, -24, getdate())
Declare #EndDate datetime = getdate()
select
dateString = convert(varchar(8),a.DateColumn,5) + '-' + convert(varchar(2),a.DateColumn, 108),
Amount = COUNT(*)
from
DbTable a
where
a.someParameter = 'test' and
a.DateColumn>= dateadd(hour, -24, getdate()) and
a.DateColumn<= getdate()
group by
convert(varchar(8),a.DateColumn,5) + '-' + convert(varchar(2),a.DateColumn, 108)
First output rows:
dateString Amount
09-12-15-14 1
09-12-15-15 1
09-12-15-16 1
09-12-15-17 3
09-12-15-18 1
09-12-15-22 3
09-12-15-23 2
As you can see here there is no data for the times from 19.00 to 21.00. This is how I want the data to be displayed:
dateString Amount
09-12-15-14 1
09-12-15-15 1
09-12-15-16 1
09-12-15-17 3
09-12-15-18 1
09-12-15-19 0
09-12-15-20 0
09-12-15-21 0
09-12-15-22 3
09-12-15-23 2
Normally, this would be approached with left join rather than outer apply. The logic is simple: keep all rows in the first table along with any matching information from the second. This means put the dates table first:
select tt.DateString, count(t.DateColumn) as Amount
from #tempTable tt left join
DbTable t
on convert(varchar(8), t.DateColumn, 5) + '-' + convert(varchar(2), t.DateColumn, 108) = tt.DateString and
t.SomeParameter = 'test'
where tt.Date >= #StartDateProc and
tt.Date <= #EndDate
group by tt.DateString;
In addition, your comparison for the dates seems overly complex, but if it works for you, it works.
The best bet here would be to use DATETIME type itself and not to lose the opportunity to use indexes:
Declare #d datetime = GETDATE()
;WITH cte1 AS(SELECT TOP 25 -1 + ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) h
FROM master..spt_values),
cte2 AS(SELECT DATEADD(hh, -h, #d) AS startdate,
DATEADD(hh, -h + 1, #d) AS enddate
FROM cte1)
SELECT c.startdate, c.enddate, count(*) as amount
FROM cte2 c
LEFT JOIN DbTable a ON a.DateColumn >= c.startdate AND
a.DateColumn < c.enddate AND
a.SomeParameter = 'test'
GROUP BY c.startdate, c.enddate
I'm a bit stumped how I might go about this.
I have a very basic query, that currently returns sales for each product, by year and month.
It is grouping by year/month, and summing up the quantity.
This returns one row for each product/year/month combo where there was a sale.
If there was no sale for a month, then there is no data.
I'd like my query to return one row of data for each product for each year/month in my date range, regardless of whether there was actually an order.
If there was no order, then I can return 0 for that product/year/month.
Below is my example query.
Declare #DateFrom datetime, #DateTo Datetime
Set #DateFrom = '2012-01-01'
set #DateTo = '2013-12-31'
select
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110) As YearMonth,
variant_detail.vad_variant_code,
sum(order_line_item.oli_qty_required) as 'TotalQty'
From
variant_Detail
join order_line_item on order_line_item.oli_vad_id = variant_detail.vad_id
join order_header on order_header.oh_id = order_line_item.oli_oh_id
Where
(order_header.oh_datetime between #DateFrom and #DateTo)
Group By
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110),
variant_detail.vad_variant_code
You can generate this by using CTE.
You will find information on this article :
http://blog.lysender.com/2010/11/sql-server-generating-date-range-with-cte/
Especially this piece of code :
WITH CTE AS
(
SELECT #start_date AS cte_start_date
UNION ALL
SELECT DATEADD(MONTH, 1, cte_start_date)
FROM CTE
WHERE DATEADD(MONTH, 1, cte_start_date) <= #end_date
)
SELECT *
FROM CTE
Thank your for your suggestions.
I managed to get this working using another method.
Declare #DateFrom datetime, #DateTo Datetime
Set #DateFrom = '2012-01-01'
set #DateTo = '2013-12-31'
select
YearMonthTbl.YearMonth,
orders.vad_variant_code,
orders.qty
From
(SELECT Convert(CHAR(4),DATEADD(MONTH, x.number, #DateFrom),120) + '/' + Convert(CHAR(2),DATEADD(MONTH, x.number, #DateFrom),110) As YearMonth
FROM master.dbo.spt_values x
WHERE x.type = 'P'
AND x.number <= DATEDIFF(MONTH, #DateFrom, #DateTo)) YearMonthTbl
left join
(select variant_Detail.vad_variant_code,
sum(order_line_item.oli_qty_required) as 'Qty',
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110) As 'YearMonth'
FROM order_line_item
join variant_detail on variant_detail.vad_id = order_line_item.oli_vad_id
join order_header on order_header.oh_id = order_line_item.oli_oh_id
Where
(order_header.oh_datetime between #DateFrom and #DateTo)
GROUP BY variant_Detail.vad_variant_code,
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110)
) as Orders on Orders.YearMonth = YearMonthTbl.YearMonth
This is what I put together. It will certainly need some debugging, but I think that this will lead you in the right direction. I broke up the queries into different parts in order to attempt to make it easier to read. Hope this helps.
DECLARE #dateFrom DATETIME, #dateTo DATETIME
SELECT #dateFrom = MIN(oh_datetime) FROM order_header
SELECT #dateTo = MAX(oh_datetime) FROM order_header
;WITH
y AS
(
SELECT YEAR(#dateFrom) AS [Year]
UNION ALL
SELECT [Year] + 1
FROM y
WHERE
[Year] < YEAR (GETDATE())
),
m AS
(
SELECT 1 AS [Month]
UNION ALL
SELECT [Month] + 1
FROM m
WHERE
[Month] < 12
),
dates AS
(
SELECT
CAST(y.[Year] AS nvarchar(4)) + N'/' + RIGHT(N'00' + CAST(m.[Month] AS nvarchar(2)), 2) AS YearMonth
FROM
y CROSS JOIN m
),
qty AS
(
SELECT
YEAR(oh.oh_datetime) + N'/' + MONTH(oh.oh_datetime) AS YearMonth,
v.vad_variant_code,
oli.oli_qty_required AS Qty
FROM
variant_Detail AS v
INNER JOIN order_line_item AS oli ON oil.oli_vad_id = v.vad_id
INNER JOIN order_header AS oh ON oh.oh_id = oli.oli_oh_id
)
SELECT
d.YearMonth,
qty.vad_variant_code,
SUM(qty.Qty) AS TotalQty
FROM
dates AS d LEFT OUTER JOIN qty
ON d.YearMonth = qty.YearMonth
GROUP BY
d.YearMonth,
qty.vad_variant_code
Here is another twist, if you find all months of a year
;WITH DateYear AS (
SELECT 0 AS num
UNION ALL
SELECT num + 1 FROM DateYear
WHERE num < 11
)
Select FirstDateOfTheMonth, DATENAME(mm,FirstDateOfTheMonth), num from
(SELECT CONVERT(DATE,DATEADD(MONTH,num,'2017')) AS FirstDateOfTheMonth, num from DateYear)
cte
and the result will be
Another twist:
Declare #dateFrom datetime ='2019-03-21', #dateTo datetime ='2019-12-31'
;WITH CTE AS
(
SELECT #dateFrom AS cte_start_date
UNION ALL
SELECT DATEADD(MONTH, 1, cte_start_date)
FROM CTE
WHERE ( DATEADD(MONTH, 1, cte_start_date) <= EOMONTH( #dateTo) )
--or ( DATENAME(MONTH, cte_start_date) =DATENAME(MONTH, #dateTo) and DATENAME(year, cte_start_date) =DATENAME(year, #dateTo) ) )
)
SELECT *
FROM CTE
This below is work for sqlserver 2012 and above to get the last day of the month :-
Select EOMONTH('2020-02-15')
I am currently working on a function in which I use a recursive CTE, but it seems that have poor performance. I need this to be in function (so no temp tables) so I can easily use it within stored procedures.
Here is the code:
CREATE FUNCTION [dbo].[Web_GetDailyLoadListUDF]
(
#CustomerID INT
, #StartDate DATETIME
, #Days INT
, #IncludeChildren BIT
)
RETURNS #TableOfValues TABLE
(
RowID SMALLINT IDENTITY(1,1)
, DailyLoadCount INT
, DailyLoadDate VARCHAR(6)
, FullDate DATETIME
)
AS
BEGIN
DECLARE #MaxDate DATETIME;
SET #MaxDate = DATEADD(dd, #Days * -1.7, DATEDIFF(dd, 0, #StartDate));
WITH DateCTE AS
(
SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, #StartDate)) AS DateValue
UNION ALL
SELECT DATEADD(DAY, -1, DateValue)
FROM DateCTE
WHERE DATEADD(DAY, -1, DateValue) > #MaxDate
)
INSERT INTO #TableOfValues
SELECT * FROM
(
SELECT TOP (#Days)
(
SELECT COUNT(*)
FROM dbo.[Load] l WITH (NOLOCK)
JOIN dbo.LoadCustomer lc WITH (NOLOCK)
ON lc.LoadID = l.ID
JOIN dbo.Customer c WITH (NOLOCK)
ON c.ID = lc.CustomerID
WHERE DATEADD(dd, 0, DATEDIFF(dd, 0, l.LoadDate)) = dct.DateValue
AND l.StateType = 1
AND lc.Main = 1
AND (c.ID = #CustomerID OR (#IncludeChildren = 1 AND c.ParentCustomerID = #CustomerID))
) AS DailyLoadCount
, CONVERT(VARCHAR(6), dct.DateValue, 107) AS DailyLoadDate
, dct.DateValue
FROM DateCTE dct
WHERE
DATEPART(DW, dct.DateValue) NOT IN (1, 7)
AND dct.DateValue NOT IN
(
SELECT HolidayDate FROM Holiday
)
ORDER BY dct.DateValue DESC
) AS S
ORDER BY s.DateValue ASC
RETURN
END
What this SQL is supposed to retrieve is the number of loads per day, for the past #Days that are business days (no weekends/holidays).
I basically just need some help optimizing this so that it doesn't run so slow. (Takes up to 20 seconds per customer, and this will be called over thousands).
Your main problem is just here
WHERE DATEADD(dd, 0, DATEDIFF(dd, 0, l.LoadDate)) = dct.DateValue
It should be
WHERE l.LoadDate >= dct.DateValue
AND l.LoadDate < dct.DateValue +1
Create composite indexs on Load(LoadDate, ID) and Load(ID, LoadDate) and drop the one that does not get used in the query plan.
You should show the query plan whenever you are asking questions about performance. To view the query plan, run the query inside the function on its own using variables for the input parameters. From the menu in SSMS, enable the option "Query -> Include Actual Execution Plan"
Since you don't have enough rep to post images, you can reveal the text plan as follows. Provide some sensible parameters in the first SELECT statement.
set showplan_text on;
Then, run the below in TEXT mode, i.e. press Ctrl-T then Ctrl-E.
DECLARE
#CustomerID INT
, #StartDate DATETIME
, #Days INT
, #IncludeChildren BIT
SELECT
#CustomerID = 1
, #StartDate = '20110201'
, #Days = 10
, #IncludeChildren = 1
DECLARE #TableOfValues TABLE
(
RowID SMALLINT IDENTITY(1,1)
, DailyLoadCount INT
, DailyLoadDate VARCHAR(6)
, FullDate DATETIME
)
DECLARE #MaxDate DATETIME;
SET #MaxDate = DATEADD(dd, #Days * -1.7, DATEDIFF(dd, 0, #StartDate));
WITH DateCTE AS
(
SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, #StartDate)) AS DateValue
UNION ALL
SELECT DATEADD(DAY, -1, DateValue)
FROM DateCTE
WHERE DATEADD(DAY, -1, DateValue) > #MaxDate
)
INSERT INTO #TableOfValues
SELECT * FROM
(
SELECT TOP (#Days)
(
SELECT COUNT(*)
FROM dbo.[Load] l WITH (NOLOCK)
JOIN dbo.LoadCustomer lc WITH (NOLOCK)
ON lc.LoadID = l.ID
JOIN dbo.Customer c WITH (NOLOCK)
ON c.ID = lc.CustomerID
WHERE DATEADD(dd, 0, DATEDIFF(dd, 0, l.LoadDate)) = dct.DateValue
AND l.StateType = 1
AND lc.Main = 1
AND (c.ID = #CustomerID OR (#IncludeChildren = 1 AND c.ParentCustomerID = #CustomerID))
) AS DailyLoadCount
, CONVERT(VARCHAR(6), dct.DateValue, 107) AS DailyLoadDate
, dct.DateValue
FROM DateCTE dct
WHERE
DATEPART(DW, dct.DateValue) NOT IN (1, 7)
AND dct.DateValue NOT IN
(
SELECT HolidayDate FROM Holiday
)
ORDER BY dct.DateValue DESC
) AS S
ORDER BY s.DateValue ASC
SELECT * FROM #TableOfValues
Edit the plan into your question
You should use an inline UDF instead (right now you are actually using a temp table)
See http://msdn.microsoft.com/en-us/library/ms189294.aspx
Or convert it into a view instead.
Correlated subqueries run row-by-row, do not use them. Use a join or a join to a derived table instead. You also need to make sure any where clauses can take advantage of the indexing. Search on saragble queries to see what kinds of things cannot use indexes and what can be done to make it use an index.