TheDoc
TheDoc

Reputation: 718

Convert ugly T SQL query to CTE

I'm having trouble making my TSQL query into a cte. I'm pretty sure it's a candidate for that. I've used cte's in other queries, but this one has to get data from multiple sources and that's causing me some grief. Here's what I've got that works:

declare @projid int         = 0
declare @proj varchar       = (select projectid from Projects where projectid = @projid)
declare @maxid int          = (select max(projectid) from Projects)
declare @projsize bigint    = (select projectsizeexpitem from Projects where projectid = @projid)
declare @numofdays int      = (select DATEDIFF(DAY, MIN(starttime), GETDATE()) from transactions where projectid = @projid)
declare @dailyrate bigint   = (select (SUM(transactionitemsmigrated)/@numofdays) from Transactions where projectid = @projid)
declare @complete bigint    = (select SUM(transactionitemsmigrated) from transactions where projectid = @projid)
declare @daysremaining int  = (select (CAST(GETDATE() AS int) + ((@projsize-@complete)/@dailyrate)))

WHILE @projid < @maxid

BEGIN
    IF @projid IN (select projectid from projects)
    BEGIN
        set @proj           = (select projectname from Projects where projectid = @projid)
        set @maxid          = (select max(projectid) from Projects)
        set @projsize       = (select projectsizeexpitem from Projects where projectid = @projid)
        set @numofdays      = (select DATEDIFF(DAY, MIN(starttime), GETDATE()) from transactions where projectid = @projid)
        set @dailyrate      = (select (SUM(transactionitemsmigrated)/@numofdays) from Transactions where projectid = @projid)
        set @complete       = (select SUM(transactionitemsmigrated) from transactions where projectid = @projid)
        set @daysremaining  = (select (CAST(GETDATE() AS int) + ((@projsize-@complete)/@dailyrate)))
        select 
            [Project]           = (select projectname from projects where projectid = @projid),
            [TotalItems]        = @projsize, 
            [DaysActive]        = @numofdays, 
            [DailyRate]         = @dailyrate, 
            [TotalComplete]     = @complete, 
            [ItemsRemaining]    = @projsize - @complete,
            [DaysRemaining]     = ((@projsize-@complete)/@dailyrate),
            [CompDate]          = CAST(CAST(@daysremaining AS datetime) AS date)
            SET @projid = @projid + 1
    END
    ELSE
    BEGIN
        SET @projid = @projid + 1
    END
END

The problem with this one is that it returns each iteration of the SELECT statement as a separate results table. I'd like to have them all together for aggregation. Here's what I've tried:

declare @projid int         = 0
declare @proj varchar       = (select projectid from Projects where projectid = @projid)
declare @maxid int          = (select max(projectid) from Projects)
declare @projsize bigint    = (select projectsizeexpitem from Projects where projectid = @projid)
declare @numofdays int      = (select DATEDIFF(DAY, MIN(starttime), GETDATE()) from transactions where projectid = @projid)
declare @dailyrate bigint   = (select (SUM(transactionitemsmigrated)/@numofdays) from Transactions where projectid = @projid)
declare @complete bigint    = (select SUM(transactionitemsmigrated) from transactions where projectid = @projid)
declare @daysremaining int  = (select (CAST(GETDATE() AS int) + ((@projsize-@complete)/@dailyrate)))

;WITH cte AS (
    select 
        [ID]                = 1,
        [Project]           = (select projectname from projects where projectid = @projid),
        [TotalItems]        = @projsize, 
        [DaysActive]        = @numofdays, 
        [DailyRate]         = @dailyrate, 
        [TotalComplete]     = @complete, 
        [ItemsRemaining]    = @projsize - @complete,
        [DaysRemaining]     = ((@projsize-@complete)/@dailyrate),
        [CompDate]          = CAST(CAST(@daysremaining AS datetime) AS date)
    UNION ALL
    select
        [ID] + 1,
        [Project]       = (select projectname from projects where projectid = @projid),
        [TotalItems]    = @projsize, 
        [DaysActive]    = @numofdays, 
        [DailyRate]     = @dailyrate, 
        [TotalComplete] = @complete, 
        [ItemsRemaining]= @projsize - @complete,
        [DaysRemaining] = ((@projsize-@complete)/@dailyrate),
        [CompDate]      = CAST(CAST(@daysremaining AS datetime) AS date)
    from cte
    where [ID] < @maxid
)

select * 
from cte
where @projid <= @maxid
OPTION (MAXRECURSION 100)

EDIT: Got it. Here's what I used. Big thanks to @Amit-Sukralia for his comment that got me to the solution!

SELECT 
    [Project]           = projectName, 
    [TotalItems]        = projectsizeexpitem,
    [DaysActive]        = (select DATEDIFF(DAY, MIN(starttime), GETDATE()) from transactions where projectid = p.projectid),
    [DailyRate]         = (select (SUM(transactionitemsmigrated)/(DATEDIFF(DAY, MIN(starttime), GETDATE()) )) from Transactions where projectid = p.projectid),
    [TotalComplete]     = (select SUM(transactionitemsmigrated) from transactions where projectid = p.projectid),
    [ItemsRemaining]    = projectsizeexpitem - (select SUM(transactionitemsmigrated) from transactions where projectid = p.projectid),
    [ExpectedCompDate]  = CAST((GETDATE() + ((p.projectsizeexpitem-(select SUM(transactionitemsmigrated) from transactions where projectid = p.projectid))/
                            (select (SUM(transactionitemsmigrated)/(DATEDIFF(DAY, MIN(starttime), GETDATE()) )) from Transactions where projectid = p.projectid))) as int) - CAST(GETDATE() as int)
FROM Projects p

Upvotes: 0

Views: 94

Answers (1)

Amit Sukralia
Amit Sukralia

Reputation: 950

You can try something like below. It doesn't require a CTE:

SELECT 
    ROW_NUMBER() OVER (PARTITION BY projectid) AS ID,
    projectName AS [Project], 
    (select max(projectid) from Projects) AS MaxId,
    projectsizeexpitem  AS [TotalItems],
    (select DATEDIFF(DAY, MIN(starttime), GETDATE()) from transactions where projectid = p.projectid) AS [DaysActive],
    (select (SUM(transactionitemsmigrated)/(DATEDIFF(DAY, MIN(starttime), GETDATE()) )) from Transactions where projectid = p.projectid) AS [DailyRate],
    (select SUM(transactionitemsmigrated) from transactions where projectid = p.projectid) AS [TotalComplete],
    projectsizeexpitem - (select SUM(transactionitemsmigrated) from transactions where projectid = p.projectid) AS [ItemsRemaining],
    (select (CAST(GETDATE() AS int) + ((projectsizeexpitem - (select SUM(transactionitemsmigrated) from transactions where projectid = p.projectid))/
                                        (select (SUM(transactionitemsmigrated)/(DATEDIFF(DAY, MIN(starttime), GETDATE()) )) from Transactions where projectid = p.projectid)))) AS [DaysRemaining]
from Projects p

Upvotes: 1

Related Questions