Use MAX(Date) value inside a SQL recursion - sql-server

I have SQL query with performs recursion based on selected Min(Date) and Max(Date) from more than 1 table. But when i try to run the query it throws GROUP BY, HAVING, or aggregate functions are not allowed in the recursive part of a recursive common table expression 'ctedaterange'. exception. I also tried using Top 1 Date but still no hope.
SQL Query
ALTER VIEW [dbo].[CYExtraction]
AS
WITH ctedaterange
AS (SELECT
[Dates] = (SELECT
MIN(CreatedOn) AS CreatedOn
FROM (SELECT
MIN(CreatedOn) AS CreatedOn
FROM (SELECT
MIN(CreatedOn) AS CreatedOn
FROM Items) AS it
UNION ALL
SELECT
*
FROM (SELECT
MIN(CreatedOn) AS CreatedOn
FROM Bibs) AS bib
UNION ALL
SELECT
*
FROM (SELECT
MIN(CreatedOn) AS CreatedOn
FROM Porders) AS po) AS AllItems)
UNION ALL
SELECT
[dates] + 1
FROM ctedaterange
WHERE [dates] + 1 <= (SELECT
MAX(CreatedOn) AS CreatedOn
FROM (SELECT
MAX(CreatedOn) AS CreatedOn
FROM (SELECT
MAX(CreatedOn) AS CreatedOn
FROM Items) AS it
UNION ALL
SELECT
*
FROM (SELECT
MAX(CreatedOn) AS CreatedOn
FROM Bibs) AS bib
UNION ALL
SELECT
*
FROM (SELECT
MAX(CreatedOn) AS CreatedOn
FROM Porders) AS po) AS AllItems))
SELECT
[Dates] AS PK_Date,
DATENAME(MONTH, [Dates]) + ' ' + CAST(YEAR([Dates]) AS varchar(4)) AS
Month,
CASE
WHEN DATEPART(m, [Dates]) <= 3 THEN 'Q1 ' + CAST(YEAR([Dates]) AS varchar(4))
ELSE CASE
WHEN DATEPART(m, [Dates]) <= 6 THEN 'Q2 ' + CAST(YEAR([Dates]) AS varchar(4))
ELSE CASE
WHEN DATEPART(m, [Dates]) <= 9 THEN 'Q3 ' + CAST(YEAR([Dates]) AS varchar(4))
ELSE CASE
WHEN DATEPART(m, [Dates]) <= 12 THEN 'Q4 ' + CAST(YEAR([Dates]) AS varchar(4))
ELSE ''
END
END
END
END AS 'Quarter',
CASE
WHEN DATEPART(m, [Dates]) <= 6 THEN 'HY1 ' + CAST(YEAR([Dates]) AS varchar(4))
ELSE CASE
WHEN DATEPART(m, [Dates]) <= 12 THEN 'HY2 ' + CAST(YEAR([Dates]) AS varchar(4))
ELSE ''
END
END AS 'HalfYear',
YEAR([Dates]) AS 'Year',
CAST('1-' AS varchar(5)) + CAST(DATEPART(M, [Dates]) AS varchar(10)) + '-' + CAST(YEAR([Dates]) AS varchar(4)) AS DateName
FROM ctedaterange
GO
The main thing is that I need to wrap it inside my SQL Views. Any help to my problem will be appreciated.
Thanks,

You can move the aggregations to an extra cte, so this might be what you want:
ALTER VIEW [dbo].[CYExtraction]
(PK_Date, [Month], [Quarter], [HalfYear], [Year], [DateName])
AS
WITH cteAllItems (mindates, maxdates) AS (
SELECT MIN(CreatedOn), MAX(CreatedOn) FROM Items
UNION ALL
SELECT MIN(CreatedOn), MAX(CreatedOn) FROM Bibs
UNION ALL
SELECT MIN(CreatedOn), MAX(CreatedOn) FROM Porders
),
ctedaterange (Dates, MaxDate) AS (
SELECT MIN(mindates), MAX(maxdates)
FROM cteAllItems
UNION ALL
SELECT DATEADD(day, 1, Dates), MaxDate
FROM ctedaterange
WHERE DATEADD(day, 1, Dates) <= MaxDate
)
SELECT
Dates AS PK_Date,
DATENAME(MONTH, Dates) + N' ' + DATENAME(YEAR, Dates),
N'Q' + DATENAME(QUARTER, Dates) + N' ' + DATENAME(YEAR, Dates),
N'HY' + CAST((MONTH(Dates)-1)/6+1 AS nvarchar(1)) + N' ' + DATENAME(YEAR, Dates),
YEAR(Dates),
CONVERT(nvarchar(10), DATEADD(MONTH, DATEDIFF(MONTH, 0, Dates), 0), 105)
FROM ctedaterange
GO

Related

Query is not grouping

Im filling a table and I need this table get the daily sells, but summing and counting, sells and clients by day respectively.
But is not grouping the sales by day this is the QUERY:
insert into VentaDiariaTienda(
Fecha,
VentaDia,
Tda_Codigo,
NumeroClientes,
PromedioVtaCliente,
EditName,
EditDateTime)
select
DATENAME(dw, T_Fecha) + ', ' +
cast(datepart(dd, T_Fecha) as char(2)) + ' ' +
datename(mm, T_Fecha) + ' ' +
cast(datepart(yyyy,T_Fecha) as char(4)),
sum(T_ImporteTotal/1.16),
[FolTda_Codigo],
count(T_Cliente),
sum(T_ImporteTotal/1.16)/count(T_Cliente),
'Admin',
GETDATE()
from #Tickets
group by T_Fecha,[FolTda_Codigo]
and this is the out of this query
Thanks for your replys.
You will have to "round down" the T_Fecha values to a day, so you might try to insert the following records:
SELECT
DATENAME(dw, dt) + ', ' +
DATENAME(dd, dt) + ' ' +
DATENAME(mm, dt) + ' ' +
DATENAME(yy, dt),
SUM(T_ImporteTotal)/1.16,
FolTda_Codigo,
COUNT(T_Cliente),
SUM(T_ImporteTotal)/1.16/COUNT(T_Cliente),
'Admin',
GETDATE()
FROM #Tickets
CROSS APPLY (
VALUES (DATEADD(day, DATEDIFF(day, 0, T_Fecha), 0))
) d (dt)
GROUP BY dt, FolTda_Codigo
My proposition:
You can use format function (since SQL Server 2012, else use Wolfgang Method)
Be carefull with divide by "Count" function. If you result is 0 (by example if T_Client is always null) you will have an error
Not necessary to use "outer apply" instruction in this case, group on by date and not by date and time
Something like this:
SELECT
FORMAT(T_Fecha, 'dddd, dd MMMM yyyy', 'en-US' ),
SUM(T_ImporteTotal)/1.16,
FolTda_Codigo,
COUNT(T_Cliente),
case when COUNT(T_Cliente)=0 then null else SUM(T_ImporteTotal)/1.16/COUNT(T_Cliente) end,
'Admin',
GETDATE()
FROM #Tickets
GROUP BY cast(T_Fecha as date), FolTda_Codigo
For SQL Server 2008, replace format by
DATENAME(dw, T_Fecha) + ', ' + DATENAME(dd, T_Fecha) + ' ' +
DATENAME(mm, T_Fecha) + ' ' + DATENAME(yy, T_Fecha),

SQL query taking very long to execute

I have two versions of the same query which I'm trying to execute on SQL Server 2008.
Version 1:
select
count(a.ordernumber) as Orders,
sum(b.agentfees) as AgentFees,
sum(a.revenue) as Revenue,
CAST('1/' + CAST(DATEPART(Month, a.closeoutdate) as varchar) + '/' + CAST(DATEPART(Year, a.closeoutdate) as varchar) as Date) as Date
from
orders a
join
[DC-SQL-V2].FaxFile.dbo.[agent fees] b on a.ordernumber = b.fforder
where
a.closeoutdate >= '2014-01-01'
and b.dtcreated >= '2014-01-01'
and a.closeoutdate < '2015-01-01'
and b.dtcreated < '2015-01-01'
and a.processserving = 1
and a.branchno = '116'
group by
CAST('1/' + CAST(DATEPART(Month, a.closeoutdate) as varchar) + '/' + CAST(DATEPART(Year, a.closeoutdate) as varchar) as Date)
order by
CAST('1/' + CAST(DATEPART(Month, a.closeoutdate) as varchar) + '/' + CAST(DATEPART(Year, a.closeoutdate) as varchar) as Date)
Version 1 takes around 3 hours to finish which is obviously insane. So I created Version 2 in which I tried to filter the tables first before joining them, but this still takes pretty long (2 hours and still going).
Version 2:
select
count(a.ordernumber) as Orders,
sum(b.agentfees) as AgentFees,
sum(a.revenue) as Revenue,
CAST('1/' + CAST(DATEPART(Month, a.closeoutdate) as varchar) + '/' + CAST(DATEPART(Year, a.closeoutdate) as varchar) as Date) as Date
from
(select
ordernumber, revenue, closeoutdate, processserving, branchno
from
ORDERS
where
closeoutdate >= '2014-01-01'
and closeoutdate < '2015-01-01'
and branchno = '116'
and processserving = 1) a
join
(select
agentfees, fforder, dtcreated
from
[DC-SQL-V2].FaxFile.dbo.[agent fees]
where
dtcreated >= '2014-01-01'
and dtcreated < '2015-01-01') b on a.ordernumber = b.fforder
group by
CAST('1/' + CAST(DATEPART(Month, a.closeoutdate) as varchar) + '/' + CAST(DATEPART(Year, a.closeoutdate) as varchar) as Date)
order by
CAST('1/' + CAST(DATEPART(Month, a.closeoutdate) as varchar) + '/' + CAST(DATEPART(Year, a.closeoutdate) as varchar) as Date)
Here are some additional details:
select count(*) from [DC-SQL-V2].FaxFile.dbo.[agent fees]
779531
select count(*) from ORDERS
3466648
Here are the clustered columns for both tables (among others that I'm not selecting):
ORDERS:
BranchNo
Closeoutdate
ProcessServing
AGENT FEES:
Nothing I'm selecting is clustered
Would someone please be able to suggest how I can improve the performance of my queries?
Assuming [DC-SQL-V2] is a remote, linked server, I'd recommend bringing that data local first.
/* Making broad assumptions here. Substitute correct data types */
CREATE TABLE #tmpAgentFees (
agentfees money,
fforder int,
dtcreated datetime
);
INSERT INTO #tmpAgentFees
(agentfees, fforder, dtcreated)
SELECT agentfees, fforder, dtcreated
FROM [DC-SQL-V2].FaxFile.dbo.[agent fees]
WHERE dtcreated >= '2014-01-01'
AND dtcreated < '2015-01-01';
/* Optionally, add an index to perhaps help performance of the join */
CREATE INDEX IX_tmpAgentFees_fforder
ON #tmpAgentFees(fforder)
INCLUDE (agentfees, dtcreated);
select count(a.ordernumber) as Orders, sum(b.agentfees) as AgentFees, sum(a.revenue) as Revenue,
CAST('1/' + CAST(DATEPART(Month, a.closeoutdate) as varchar) + '/' + CAST(DATEPART(Year, a.closeoutdate) as varchar) as Date) as Date
from orders a
join #tmpAgentFees b
on a.ordernumber = b.fforder
where a.closeoutdate >= '2014-01-01'
and a.closeoutdate < '2015-01-01'
and a.processserving=1
and a.branchno='116'
group by
CAST('1/' + CAST(DATEPART(Month, a.closeoutdate) as varchar) + '/' + CAST(DATEPART(Year, a.closeoutdate) as varchar) as Date)
order by
CAST('1/' + CAST(DATEPART(Month, a.closeoutdate) as varchar) + '/' + CAST(DATEPART(Year, a.closeoutdate) as varchar) as Date)
There are some general hints
use SQL Server Profiler to find the most costly part
use an index on join column fforder
CAST('1/' + CAST(DATEPART(Month, a.closeoutdate) as varchar) + '/' + CAST(DATEPART(Year, a.closeoutdate) as varchar) as Date) is repeated again and again, if it is possible create a computer column in your table and store the value and create an index on this new column with include in index option on
if 3 is not possible use drive table for example as below
select * from
(
select col1,col2,..,CAST('1/' + CAST(DATEPART(Month, a.closeoutdate) as varchar) + '/' + CAST(DATEPART(Year, a.closeoutdate) as varchar) as Date) from table1 ) drivedTable
join .....
The costly part is where you are getting detail data from the foreign server and then summarizing it. You should summarize it their and then only bring that back. It is not clear to me how "dtcreated" and "closeoutdate" are related?
Below I summarized the data by month and then brought it over to the local server. So only 12 rows are coming over instead of one per order. This may not be what you want if the fee should be counted in the "closeoutdate" month. But your code had a problem where it would never count an order or fee if there dates were in different years. (Need to clarify what is needed with that.)
select
a.CloseMonth,
a.Orders,
b.AgentFees
a.Revenue
from
(select year(closeoutdate) * 100 + month(closeoutdate) as CloseMonth,
count(a.ordernumber) as Orders,
sum(a.revenue) as Revenue
from orders
where closeoutdate >= '2014-01-01'
and closeoutdate < '2015-01-01'
and branchno = '116'
and processserving = 1
group by year(closeoutdate) * 100 + month(closeoutdate)) as a
join
(select year(dtcreated) * 100 + month(dtcreated) as FeeMonth,
sum(agentfees) AgentFees
from [DC-SQL-V2].FaxFile.dbo.[agent fees]
where
dtcreated >= '2014-01-01'
and dtcreated < '2015-01-01'
group by year(dtcreated) * 100 + month(dtcreated)) b
on a.CloseMonth = b.FeeMonth
order by a.CloseMonth

Getting Error when converting to datetime :Date Column + Time Column

Below is my sql query, Inner query returning the value but outer query returning error:
"Conversion failed when converting character string to smalldatetime data type. "
SELECT x.*
FROM (
SELECT
Convert(SMALLDATETIME, Convert(VARCHAR(30), Convert(DATE, Event_Date, 101)) +
Convert(VARCHAR(30), ' ') + Convert(VARCHAR(30), Convert(TIME, Event_Time)), 101)
,[Event_Date]
,Location
,Street
,City
,[State]
,Country
,ZipCode
,[Subject]
,[Detail]
,[LeadInstructor]
,[CoInstructor]
FROM [Temp_EVT_EVENT]
) x
SMALLDATE can accept time value upto 18:00:00. But you used TIME format 18:00:00.000000 that is why it show error. Check the query and update the status.
First run this query separately:
SELECT
Convert(SMALLDATETIME, Convert(VARCHAR(30), Convert(DATE, CAST('2014-11-14' AS DATETIME), 101)) +
Convert(VARCHAR(30), ' ') + Convert(VARCHAR(30), CONVERT(VARCHAR(8), CAST('18:13:04' AS DATETIME), 108)), 101) AS column1
if you get the answer. '2014-11-14 18:13:00'
Then try to run:
SELECT
Convert(SMALLDATETIME, Convert(VARCHAR(30), Convert(DATE, CAST(Event_Date AS DATETIME), 101)) +
Convert(VARCHAR(30), ' ') + Convert(VARCHAR(30), CONVERT(VARCHAR(8), CAST(Event_Time AS DATETIME), 108)), 101) AS column1 FROM Temp_EVT_EVENT
if you get the answer correctly. Then Run:
SELECT x.*
FROM (
SELECT
Convert(SMALLDATETIME, Convert(VARCHAR(30), Convert(DATE, CAST(Event_Date AS DATETIME), 101)) +
Convert(VARCHAR(30), ' ') + Convert(VARCHAR(30), CONVERT(VARCHAR(8), CAST(Event_Time AS DATETIME), 108)), 101) AS column1
,[Event_Date]
,Location
,Street
,City
,[State]
,Country
,ZipCode
,[Subject]
,[Detail]
,[LeadInstructor]
,[CoInstructor]
FROM [Temp_EVT_EVENT]
) x
Basing on your Event_Date format, look here: Date Formats
It seems that the correct format is 120, and not 101.
So:
SELECT x.*
FROM (
SELECT
Convert(SMALLDATETIME, Convert(VARCHAR(30), Convert(DATE, Event_Date, 120)) +
Convert(VARCHAR(30), ' ') + Convert(VARCHAR(30), Convert(TIME, Event_Time)), 120)
,[Event_Date]
,Location
,Street
,City
,[State]
,Country
,ZipCode
,[Subject]
,[Detail]
,[LeadInstructor]
,[CoInstructor]
FROM [Temp_EVT_EVENT]
) x

SQL Server stored procedure to produce a calendar

I have a stored procedure that returns the timeslots throughout the day, along with the capacity for each timeslot.
ALTER PROCEDURE [dbo].[TimeSlots_Sel]
(
#dateReqd date,
#typeReqd varchar(5) = 'ATI'
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #timeNow time(0) = CONVERT(time(0),GETDATE())
IF #dateReqd >= CONVERT(date, GETDATE())
BEGIN
DECLARE #tblWIP AS dbo.tvpWIP
INSERT INTO #tblWIP
SELECT [Type], [status_id], Scheduled_Call
FROM dbo.WIP
WHERE status_id = 70
AND Scheduled_Call >= #dateReqd
AND Scheduled_Call < DATEADD(dd,1,#dateReqd)
SELECT ts.SlotTime,
dbo.funCapacity(#tblWIP, #dateReqd, ts.SlotTime, #typeReqd) AS [Capacity]
FROM dbo.TimeSlots ts
WHERE NOT EXISTS
(
SELECT *
FROM dbo.Downtime dt
WHERE dbo.funStrToDateTime(YEAR(#dateReqd),MONTH(#dateReqd),DAY(#dateReqd), DATEPART(HOUR, ts.SlotTime),DATEPART(MINUTE, ts.SlotTime))
BETWEEN
dbo.funStrToDateTime(YEAR(#dateReqd),dt.StartMonth, dt.StartDay, dt.StartHour, dt.StartMin)
AND dbo.funStrToDateTime(YEAR(#dateReqd),dt.EndMonth, dt.EndDay, dt.EndHour, dt.EndMin)
)
AND dbo.funCapacity(#tblWIP, #dateReqd, ts.SlotTime, #typeReqd) > 0
AND
(
#dateReqd > GETDATE()
OR
ts.SlotTime >= #timeNow
)
ORDER BY SlotTime
END
END
So I get information like this
SlotTime Capacity
--------------------
09:00:00 3
09:30:00 3
10:00:00 3
10:30:00 3
11:00:00 3
11:30:00 2
12:00:00 2
12:30:00 2
But now I need to display a grid showing capacity for the next 7 days by date. Any ideas how I could modify the stored procedure to return something like this
SlotTime Sun 14/11/2010 Mon 15/11/2010 Tue 16/11/2010 Wed 17/11/2010 Thu 18/11/2010 Fri 19/11/2010 Sat 20/11/2010
09:00:00 3 3 3 1 3 1 1
09:30:00 3 3 3 3 3 3 3
10:00:00 3 3 3 1 3 3 3
10:30:00 3 3 3 1 3 1 2
11:00:00 3 3 3 3 3 3 3
11:30:00 3 3 3 1 3 3 3
I do have a similar procedure for creating a calendar which does a similar thing but I am finding it very difficult to display what I want. Here is the other stored procedure:
ALTER PROCEDURE [dbo].[Calendar_Sel] ( #StartDate DATE )
AS
BEGIN
SET NOCOUNT ON
DECLARE #EndDate DATE = DATEADD(Day,6,#StartDate)
DECLARE #dates VARCHAR(MAX)
DECLARE #datevals VARCHAR(MAX)
DECLARE #sql NVARCHAR(MAX)
DECLARE #ParmDefinition NVARCHAR(100)
;WITH cte AS
(
SELECT #StartDate AS DateColumn UNION ALL
SELECT DATEADD(Day,1,DateColumn) FROM cte WHERE DateColumn < #EndDate
)
SELECT DateColumn INTO #temp FROM cte
SET #dates = STUFF((SELECT ',[' + CONVERT(VARCHAR,DateColumn,112) + ']' FROM #temp FOR XML PATH('') ),1,1,'')
SET #datevals = STUFF((SELECT ',COALESCE([' + CONVERT(VARCHAR,DateColumn,112) + '],'''') AS [' + CONVERT(VARCHAR,DateColumn,112) + ']' FROM #temp FOR XML PATH('') ),1,1,'')
SET #sql = '
DECLARE #EndDate DATE = DATEADD(Day,6,#StartDate)
;WITH cte AS
(
SELECT #StartDate AS DateColumn UNION ALL
SELECT DATEADD(Day,1,DateColumn) FROM cte WHERE DateColumn < #EndDate
)
,cte1 AS
(
SELECT DISTINCT r.RoomID, CONVERT(VARCHAR,DateColumn,112) AS DateColumn,
CAST(CASE WHEN EXISTS(SELECT * FROM dbo.Payments WHERE BookingID = b.BookingID) THEN 1 ELSE 0 END AS CHAR(1))
+ CAST(b.BookingID AS CHAR(15)) + c.Surname AS CompoundKey
FROM dbo.Bookings b
JOIN dbo.BookingsDetails bd
ON b.BookingID = bd.BookingID
JOIN dbo.Customers c
ON c.CustomerId = b.CustomerId
JOIN dbo.Rooms r
ON r.RoomId = bd.RoomId
JOIN cte
ON cte.DateColumn BETWEEN b.DateArrive AND DATEADD(Day,-1,b.DateLeave)
)
SELECT Room,
Price1 = dbo.funStayPrice(#StartDate,DATEADD(Day,1,#StartDate),RoomTypeID,0),
Price2 = dbo.funStayPrice(DATEADD(Day,1,#StartDate),DATEADD(Day,2,#StartDate),RoomTypeID,0),
Price3 = dbo.funStayPrice(DATEADD(Day,2,#StartDate),DATEADD(Day,3,#StartDate),RoomTypeID,0),
Price4 = dbo.funStayPrice(DATEADD(Day,3,#StartDate),DATEADD(Day,4,#StartDate),RoomTypeID,0),
Price5 = dbo.funStayPrice(DATEADD(Day,4,#StartDate),DATEADD(Day,5,#StartDate),RoomTypeID,0),
Price6 = dbo.funStayPrice(DATEADD(Day,5,#StartDate),DATEADD(Day,6,#StartDate),RoomTypeID,0),
Price7 = dbo.funStayPrice(DATEADD(Day,6,#StartDate),DATEADD(Day,7,#StartDate),RoomTypeID,0),
SUBSTRING([' + CONVERT(VARCHAR,#StartDate,112) + '],16,12) AS Entry1,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,1,#StartDate),112) + '],16,12) AS Entry2,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,2,#StartDate),112) + '],16,12) AS Entry3,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,3,#StartDate),112) + '],16,12) AS Entry4,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,4,#StartDate),112) + '],16,12) AS Entry5,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,5,#StartDate),112) + '],16,12) AS Entry6,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,6,#StartDate),112) + '],16,12) AS Entry7,
SUBSTRING([' + CONVERT(VARCHAR,#StartDate,112) + '],2,15) AS ID1,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,1,#StartDate),112) + '],2,15) AS ID2,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,2,#StartDate),112) + '],2,15) AS ID3,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,3,#StartDate),112) + '],2,15) AS ID4,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,4,#StartDate),112) + '],2,15) AS ID5,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,5,#StartDate),112) + '],2,15) AS ID6,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,6,#StartDate),112) + '],2,15) AS ID7,
SUBSTRING([' + CONVERT(VARCHAR,#StartDate,112) + '],1,1) AS Status1,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,1,#StartDate),112) + '],1,1) AS Status2,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,2,#StartDate),112) + '],1,1) AS Status3,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,3,#StartDate),112) + '],1,1) AS Status4,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,4,#StartDate),112) + '],1,1) AS Status5,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,5,#StartDate),112) + '],1,1) AS Status6,
SUBSTRING([' + CONVERT(VARCHAR,DATEADD(Day,6,#StartDate),112) + '],1,1) AS Status7
FROM
(
SELECT r.RoomName, r.RoomName + '' ['' + rt.TypeDescription + '']'' AS Room, rt.RoomTypeID, '+ #datevals + '
FROM cte1
PIVOT (MAX(CompoundKey) FOR DateColumn IN (' + #dates + ')) AS p
RIGHT OUTER JOIN dbo.Rooms r
ON r.RoomID = p.RoomID
JOIN dbo.RoomTypes rt
ON rt.RoomTypeID = r.RoomTypeID
) x
ORDER BY CASE WHEN ISNUMERIC(RoomName) = 1 THEN CAST(RoomName AS INT) ELSE 0 END, RoomName';
SET #ParmDefinition = N'#StartDate DATE';
EXEC sp_executesql #sql, #ParmDefinition,
#StartDate = #StartDate;
END
If anyone could help me to return the capacity table I would be very grateful. I am looking to display this information in a GridView and already have the column headings, so I just need the right stored procedure with the data.
Thanks very very much for any help. Any suggestions I am sure would be a great help.
I've tried to simplify your request down a bit and come up with this solution. Basically, we are getting a list of dates and times cross joined with a function to get the capacity (i used a random number here) then pivoting on the dates. Since the columns will be dynamic, we need to use a dynamic query to get the column headers.
Hopefully, you can use this to apply to your own query.
CREATE TABLE #TimeSlots (SlotTime TIME)
INSERT INTO #TimeSlots VALUES ('09:00:00')
INSERT INTO #TimeSlots VALUES ('09:30:00')
INSERT INTO #TimeSlots VALUES ('10:00:00')
INSERT INTO #TimeSlots VALUES ('10:30:00')
INSERT INTO #TimeSlots VALUES ('11:00:00')
INSERT INTO #TimeSlots VALUES ('11:30:00')
CREATE TABLE #DateSlots (Dates DATE)
INSERT INTO #DateSlots VALUES (GETDATE())
INSERT INTO #DateSlots VALUES (DATEADD(DAY, 1, GETDATE()))
INSERT INTO #DateSlots VALUES (DATEADD(DAY, 2, GETDATE()))
INSERT INTO #DateSlots VALUES (DATEADD(DAY, 3, GETDATE()))
INSERT INTO #DateSlots VALUES (DATEADD(DAY, 4, GETDATE()))
INSERT INTO #DateSlots VALUES (DATEADD(DAY, 5, GETDATE()))
INSERT INTO #DateSlots VALUES (DATEADD(DAY, 6, GETDATE()))
INSERT INTO #DateSlots VALUES (DATEADD(DAY, 7, GETDATE()))
DECLARE #PivotColumnHeaders VARCHAR(MAX)
SELECT #PivotColumnHeaders = COALESCE(#PivotColumnHeaders + ',[' + CAST(Dates AS VARCHAR) + ']', '[' + CAST(Dates AS VARCHAR) + ']')
FROM #DateSlots
WHERE Dates BETWEEN GETDATE() AND DATEADD(DAY, 7, GETDATE())
DECLARE #PivotTableSQL NVARCHAR(MAX)
SET #PivotTableSQL = N'
SELECT *
FROM (
SELECT SlotTime, cast(Dates as varchar) Dates, Abs(Checksum(NewId())) % 4 AS Capacity
FROM #TimeSlots
CROSS JOIN #DateSlots
WHERE Dates BETWEEN GETDATE() AND DATEADD(DAY, 7, GETDATE())
) AS Source
PIVOT
(
MAX(Capacity)
FOR Dates IN (
' + #PivotColumnHeaders + '
)
) AS PivotTable
'
EXECUTE(#PivotTableSQL)
DROP TABLE #TimeSlots
DROP TABLE #DateSlots

Conditional Common Table Expression (CTE) in SQL

I'm trying to select the hierarchy of a product category tree in SQL.
My code looks as follows. I'm trying to achieve a dynamic sort order, using IF or Case When on the SortOrder parameter.
The commented line should be active if #SortOrder is equal to 'sortorder'. I tried to add If Else statement around it, but I failed...
Can you help?
CREATE PROCEDURE [dbo].[ProductCategory_SelectHierarchy]
#SortOrder varchar(30)
AS
SET NOCOUNT ON;
WITH Categories (Id,ParentId,SortOrder,RowOrder) as
(
SELECT parentCategory.Id,
parentCategory.ParentId,
parentCategory.SortOrder,
--cast(REPLACE(STR(parentCategory.SortOrder, 8), ' ', '0') as varchar(30)) 'RowOrder'
cast(CAST(DATEPART(YEAR, parentCategory.DateCreated) as varchar(4)) +
CAST(DATEPART(MONTH, parentCategory.DateCreated) as varchar(2)) +
CAST(DATEPART(DD, parentCategory.DateCreated) as varchar(2)) +
CAST(DATEPART(HOUR, parentCategory.DateCreated) as varchar(2)) as varchar(50)) 'RowOrder'
FROM ProductCategories parentCategory
WHERE ParentId = 0
UNION ALL
SELECT childCategories.Id,
childCategories.ParentId,
childCategories.SortOrder,
--cast(Categories.RowOrder + REPLACE(STR(childCategories.SortOrder, 8), ' ', '0') as varchar(30)) 'RowOrder'
cast(Categories.RowOrder + '/' + CAST(DATEPART(YEAR, childCategories.DateCreated) as varchar(4)) +
CAST(DATEPART(MONTH, childCategories.DateCreated) as varchar(2)) +
CAST(DATEPART(DD, childCategories.DateCreated) as varchar(2)) +
CAST(DATEPART(HOUR, childCategories.DateCreated) as varchar(2)) as varchar(50)) 'RowOrder'
FROM ProductCategories childCategories
JOIN Categories
ON childCategories.ParentId = Categories.Id
)
SELECT pc.*, Categories.RowOrder
FROM Categories
INNER JOIN ProductCategories pc ON pc.Id = Categories.Id
ORDER BY RowOrder
You should be able to sort it like so:
ORDER BY
CASE
WHEN #SortOrder = 'date_column' THEN CONVERT(VARCHAR(20), date_column, 120)
WHEN #SortOrder = 'customer_id' THEN RIGHT(REPLICATE('0', 20) + CAST(customer_id AS VARCHAR(20)), 20)
WHEN #SortOrder = 'name' THEN name
ELSE sort_order
END
The key is getting all of your sortable columns (or expressions) to end up as the same data type.

Resources