sum (case when else end) statement - sql

I have a SQL Server SQL statement that works but it is seemingly messy and inefficient. It checks each row of data for its data and groups it into Yesterday, WeektoDate, MonthtoDate, and YeartoDate and sums each field by the group. Is there a better way to do this?
Below is a sample of what I have, there are actually 15 or so fields in the actual query, which makes for a long SELECT query, Is there a better way to do this?
SELECT
sum(CASE when row_date BETWEEN #YesterdayMorning and #EndOfYesterday THEN Total_Calls ELSE 0 END) AS Calls_Yesterday
,sum(CASE when row_date BETWEEN #YesterdayMorning AND #EndOfYesterday THEN Total_Time ELSE 0 END) AS Time_Yesterday
,sum(CASE when row_date BETWEEN #WTDMorning and #EndOfYesterday THEN Total_Calls ELSE 0 END) AS Calls_WTD
,sum(CASE when row_date BETWEEN #WTDMorning AND #EndOfYesterday THEN Total_Time ELSE 0 END) AS Time_WTD
,sum(CASE when row_date BETWEEN #MTDMorning and #EndOfYesterday THEN Total_Calls ELSE 0 END) AS Calls_MTD
,sum(CASE when row_date BETWEEN #MTDMorning AND #EndOfYesterday THEN Total_Time ELSE 0 END) AS Time_MTD
,sum(CASE when row_date BETWEEN #YTDMorning and #EndOfYesterday THEN Total_Calls ELSE 0 END) AS Calls_YTD
,sum(CASE when row_date BETWEEN #YTDMorning AND #EndOfYesterday THEN Total_Time ELSE 0 END) AS Time_YTD
FROM TableName

One option is to get rid of the CASE, break them into multiple SELECT queries with WHERE conditions and then union them:
SELECT
'Yesterday' AS Range
SUM(Total_Calls) AS Calls,
SUM(Total_Time) AS Time
FROM TableName
WHERE row_date BETWEEN #YesterdayMorning AND #EndOfYesterday
UNION
SELECT
'WTD' AS Range,
SUM(Total_Calls) AS Calls,
SUM(Total_Time) AS Time
FROM TableName
WHERE row_date BETWEEN #WTDMorning AND #EndOfYesterday
UNION
SELECT
'MTD' AS Range,
SUM(Total_Calls) AS Calls,
SUM(Total_Time) AS Time
FROM TableName
WHERE row_date BETWEEN #MTDMorning AND #EndOfYesterday
UNION
SELECT
'YTD' AS Range,
SUM(Total_Calls) AS Calls,
SUM(Total_Time) AS Time
FROM TableName
WHERE row_date BETWEEN #YTDMorning AND #EndOfYesterday

I do not think your query is that inefficient, the query plan looks ok, but I agree the code is a bit messy. I would consider some thing like this to avoid the duplicated code:
Add all morning dates to a table
Join dates to the call table
SUM calls and call time
Query:
DECLARE #day VARCHAR(2) = FORMAT(DAY(GETDATE()), '00'), #month VARCHAR(2) = FORMAT(MONTH(GETDATE()), '00'), #year INT = YEAR(GETDATE());
DECLARE #weekday INT = DATEPART(dw, GETDATE());
DECLARE #morningTime TIME = '08:00';
DECLARE #EndOfYesterday DATETIME2 = DATEADD(dd, -1, CONVERT(DATETIME2, CONCAT(YEAR(GETDATE()), MONTH(GETDATE()), DAY(GETDATE()), ' 18:00')));
DECLARE #timeTable TABLE(ID INT IDENTITY(1,1) PRIMARY KEY, Name VARCHAR(255), FromDate DATETIME2);
INSERT INTO #timeTable
SELECT 'Yesterday', DATEADD(dd, -1, CONVERT(DATETIME2, CONCAT(#year, #month, #day, ' ', #morningTime)))
UNION ALL SELECT 'WTDMorning', DATEADD(dd, -(#weekday-1), CONVERT(DATETIME2, CONCAT(#year, #month, #day, ' ', #morningTime)))
UNION ALL SELECT 'MTDMorning', CONVERT(DATETIME2, CONCAT(#year, #month, '01', ' ', #morningTime))
UNION ALL SELECT 'YTDMorning', CONVERT(DATETIME2, CONCAT(#year, '01', '01', ' ', #morningTime))
SELECT t.Name, Total_Calls = SUM(c.Total_Calls), Total_Time = SUM(c.Total_Time)
FROM #timeTable t
LEFT JOIN TableName c ON c.row_date BETWEEN t.FromDate AND #EndOfYesterday
GROUP BY ID, t.Name
ORDER BY ID
On my test data your query actually have a 15% lower query cost that my query, but with an index on the "call table" my query is 20% cheaper then yours.
Index:
CREATE NONCLUSTERED INDEX idxRowDate
ON [dbo].[TableName] ([row_date])
INCLUDE ([Total_Calls],[Total_Time])
I am aware that this do not match your output 100%, but I do believe that rows are easier to work with than 15+ columns. This could also be converted to one row if needed.
One row support:
If it is needed, you could convert the rows to one line with dynamic sql. But it gets a bit more complex:
DECLARE #onRowconverter VARCHAR(MAX) = '';
SELECT #onRowconverter = #onRowconverter + CASE WHEN #onRowconverter > '' THEN ', ' ELSE 'SELECT ' END + CONCAT('[Calls_' + t.Name + '] = ', SUM(c.Total_Calls), ', [Time_' + t.Name + '] = ', SUM(c.Total_Time))
FROM #timeTable t
LEFT JOIN TableName c ON c.row_date BETWEEN t.FromDate AND #EndOfYesterday
GROUP BY ID, t.Name
ORDER BY ID
EXEC(#onRowconverter);

Related

How to write a loop for such sql query

I need to write such query:
SELECT CAST (date_time_column AS DATE) as 'Date',
AVG(CASE WHEN FORMAT(date_time_column, 'HH:mm') = '00:00' then my_values ELSE NULL end) as '00:00',
........
AVG(CASE WHEN FORMAT(date_time_column, 'HH:mm') = '23:59' then my_values ELSE NULL end) as '23:59'
FROM table
where date_time_column > '2021-08-12'
GROUP BY CAST (date_time_column AS DATE)
What is a way to avoid writing 1440 lines in a query?
Try the below method (Change the variables to match your table and field)
/*Generate all minutes in a day in a string variable*/
Declare #timeRange varchar(max)=null
declare #startdate Datetime='2021-08-12 00:00';
; WITH cte AS
(
SELECT 1 i, #startdate AS resultDate
UNION ALL
SELECT i + 1, DATEADD(minute, i, #startdate )
FROM cte
WHERE DATEADD(minute, i, #startdate ) < DateAdd(day,1,#startdate)
)
SELECT #timeRange=Coalesce(#timeRange +',' + '['+Format(resultDate,'HH:mm')+']','['+Format(resultDate,'HH:mm')+']') FROM cte
OPTION (MAXRECURSION 2000);
/* (Change These variables to match your table & fields */
declare #filterQuery varchar(300)=' where {date_time_column}>''2021-01-01''';
declare #dateTimeColumn varchar(30)='{date_time_column}';
declare #valueColumn varchar(30)='{value_column}';
declare #myTable varchar(20)='{my_table}';
/*Generate Pivot Query */
DECLARE #query AS NVARCHAR(MAX);
set #query= '
SELECT *
FROM (SELECT Cast('+ #dateTimeColumn +' as Date) Resultdate,
       FORMAT(' + #dateTimeColumn + ', ''HH:mm'') DateMinute,
       ' + #valueColumn + ' FROM ' + #myTable + ' ' + #filterQuery +'
     ) FormattedData
PIVOT( AVG('+ #valueColumn + ')  
    FOR DateMinute IN ('+ #timeRange +')
) AS pivotTable
';
/*Execute Generated Query*/
execute(#query)
What you want to do is to return your data in rows, not columns. That is a row for every minute rather than a column for every minute.
Try it something like this:
WITH
cteNums AS
(
Select TOP (1440) ROW_NUMBER() OVER(order by (Select Null)) - 1 as num
From sys.all_columns
Order By num
)
, cteMinutes AS
(
Select FORMAT(CAST(num/cast(1440.0 as real) as DATETIME), N'HH:mm') as Minutes
From cteNums
)
select CAST(t.date_time_column AS DATE) as 'Date',
m.Minutes,
AVG(CASE WHEN FORMAT(t.date_time_column, 'HH:mm') = m.Minute then t.my_values ELSE NULL end) as AvgValues
FROM cteMinutes m
LEFT JOIN [table] t ON m.Minutes = FORMAT(t.date_time_column, 'HH:mm')
where t.date_time_column > '2021-08-12'
GROUP BY CAST(t.date_time_column AS DATE), m.Minutes
ORDER BY CAST(t.date_time_column AS DATE), m.Minutes
;
I cannot, of course, test this as no test data or table definitions were provided.

Query with Join of tables is taking long time to execute 5 min

SELECT
B.AccountBranchID
,B.VoucherNo
,B.BranchName AS BranchName
,B.InvoiceNo
,CONVERT(VARCHAR, B.InvoiceDate, 103) AS InvoiceDate
,CONVERT(VARCHAR, B.VoucherDate, 103) AS VoucherDate
,B.CustomerName
,B.RefID
,LN.AccountName AS LedgerName
,b.SalesPersonName AS SalesPersonName
,LN.LedgerCode
,B.AgentName
,B.ShipperName
,B.Segment
,B.TransactionType
,B.JobNo
,CONVERT(VARCHAR, B.JOBDate, 103) AS JOBDate
,B.MAWBNo
,B.HAWBNo
,B.AccountName
,B.LedgerCode AS AccountLedgerCode
,B.CurrencyCode
,ISNULL(B.Amount, 0) AS Amount
,B.ChargeExRate
,(CASE B.CRDR
WHEN 'CR' THEN (B.ChargeBaseAmount * -1)
ELSE B.ChargeBaseAmount
END) AS ChargeBaseAmount
,(CASE B.CRDR
WHEN 'CR' THEN 'Credit'
ELSE 'Debit'
END) AS CRDR
FROM VW_VoucherTR AS B
INNER JOIN VW_VoucherTR AS LN
ON B.VoucherID = LN.VoucherID
WHERE B.CompanyID = #CompanyID
AND (CASE #Type
WHEN 'I' THEN B.InvoiceDate
ELSE B.VoucherDate
END) BETWEEN ISNULL(#FromDate, (SELECT
FYearStart
FROM Secmst_FinancialYear
WHERE FyearId = #yearID)
) AND ISNULL(#ToDate, GETDATE())
AND (#Segment IS NULL
OR B.Segment = #Segment)
AND (#BranchMappingID IS NULL
OR B.BranchMappingID = #BranchMappingID)
AND B.VoucherTypeCode IN ('sv')
AND B.IsDeleted = 0
AND (B.GroupName <> 'Sundry Creditors'
AND B.GroupName <> 'Sundry Debtors')
AND LN.GroupName IN ('Sundry Debtors', 'Sundry Creditors')
The subquery in the BETWEEN is probably what is killing you. Have you looked at the execution plan?
BETWEEN ISNULL(#FromDate, (
SELECT FYearStart
FROM Secmst_FinancialYear
WHERE FyearId = #yearID
))
AND ISNULL(#ToDate, GETDATE())
What's happening is you are running that query across every row, and by my looks, that's unnecessary because you are only needing static dates there (not anything based on the joined rows.)
Try this:
DECLARE #FromDateActual datetime = ISNULL(#FromDate, (
SELECT FYearStart
FROM Secmst_FinancialYear
WHERE FyearId = #yearID
));
DECLARE #ToDateActual datetime = ISNULL(#ToDate, GETDATE());
SELECT B.AccountBranchID
,B.VoucherNo
,B.BranchName AS BranchName
,B.InvoiceNo
,convert(VARCHAR, B.InvoiceDate, 103) AS InvoiceDate
,convert(VARCHAR, B.VoucherDate, 103) AS VoucherDate
,B.CustomerName
,B.RefID
,LN.AccountName AS LedgerName
,b.SalesPersonName AS SalesPersonName
,LN.LedgerCode
,B.AgentName
,B.ShipperName
,B.Segment
,B.TransactionType
,B.JobNo
,convert(VARCHAR, B.JOBDate, 103) AS JOBDate
,B.MAWBNo
,B.HAWBNo
,B.AccountName
,B.LedgerCode AS AccountLedgerCode
,B.CurrencyCode
,ISNULL(B.Amount, 0) AS Amount
,B.ChargeExRate
,(
CASE B.CRDR
WHEN 'CR'
THEN (B.ChargeBaseAmount * - 1)
ELSE B.ChargeBaseAmount
END
) AS ChargeBaseAmount
,(
CASE B.CRDR
WHEN 'CR'
THEN 'Credit'
ELSE 'Debit'
END
) AS CRDR
FROM VW_VoucherTR AS B
INNER JOIN VW_VoucherTR AS LN ON B.VoucherID = LN.VoucherID
WHERE B.CompanyID = #CompanyID
AND (
CASE #Type
WHEN 'I'
THEN B.InvoiceDate
ELSE B.VoucherDate
END
) BETWEEN #FromDateActual
AND #ToDateActual
AND (
#Segment IS NULL
OR B.Segment = #Segment
)
AND (
#BranchMappingID IS NULL
OR B.BranchMappingID = #BranchMappingID
)
AND B.VoucherTypeCode IN ('sv')
AND B.IsDeleted = 0
AND (
B.GroupName <> 'Sundry Creditors'
AND B.GroupName <> 'Sundry Debtors'
)
AND LN.GroupName IN (
'Sundry Debtors'
,'Sundry Creditors'
)
Beyond that you could consider adding non-clustered indexes. The Query Analyzer may even suggest a couple. But you'll want to be careful there, depending on how the data is used and loaded, as too many indexes or large ones can lead to further performance issues in other places (row insertions, page fragmentation, etc).
There could be many reasons for it, but one thing is quite plain. The following part is not sargable.
(CASE #Type
WHEN 'I' THEN B.InvoiceDate
ELSE B.VoucherDate
END) BETWEEN ISNULL(#FromDate, (SELECT
FYearStart
FROM Secmst_FinancialYear
WHERE FyearId = #yearID)
) AND ISNULL(#ToDate, GETDATE())
Should be rewritten to be sargable, so that indexes can be used.
SELECT #FromDate = ISNULL(#FromDate, (SELECT
TOP 1 FYearStart
FROM Secmst_FinancialYear
WHERE FyearId = #yearID)) )
SELECT #ToDate = ISNULL(#ToDate, GETDATE())
SELECT
...
WHERE
...
AND
((#Type='I' AND B.InvoiceDate BETWEEN #FromDate AND #ToDate)
OR
(#Type<>'I' AND B.VoucherDate BETWEEN #FromDate AND #ToDate))
AND
...
Of course proper indexing is the way how to speed up your query, if no indexes are on InvoiceDate, VoucherDate, etc. then your query will use full table scan instead of index seek and it will be slow.

SQL Server : multi-part identifier could not be bound

I need a simple output of fields named "36" - "1" with the extended inventory value for everything in the specified item classes. I don't need itemization.
E.g.
Error is:
"Database Connector Error. '42000:[Microsoft][ODBC SQL Server Driver][SQL Server]The multi-part identifier "InvenFiscPerHistTable.FiscalPeriod" could no be bound. [Database Vendor Code: 4104 ]'
Here's my SQL.
DECLARE #CalMonth INT
DECLARE #CalYear INT
DECLARE #CalMoYear DATETIME
SET #CalMonth = CASE WHEN "InvenFiscPerHistTable"."FiscalPeriod" IN (1,2,3) THEN "InvenFiscPerHistTable"."FiscalPeriod" + 9 ELSE "InvenFiscPerHistTable"."FiscalPeriod" - 3 END
SET #CalYear = CASE WHEN "InvenFiscPerHistTable"."FiscalPeriod" IN (1,2,3) THEN "InvenFiscPerHistTable"."FiscalYear" + 1 ELSE "InvenFiscPerHistTable"."FiscalYear" END
SET #CalMoYear = CAST(CONVERT(NVARCHAR, #CalYear) + '-' + CONVERT(NVARCHAR, #CalMonth) + '-' + CONVERT(NVARCHAR,1) AS DATETIME)
--our fiscal year is not the same as the calendar year
--e.g. FiscalPeriod = 1 and FiscalYear = 2016 will be October 2015
SELECT SUM (CASE WHEN #CalMoYear BETWEEN DATEADD(m, -36, GETDATE()-day(GETDATE()-1)) AND DATEADD(m, -35, GETDATE()-day (GETDATE()-1))-1 THEN"InvenFiscPerHistTable"."QOH" * "InvenTable"."UnitCost" ELSE NULL END) AS "36"
,SUM (CASE WHEN #CalMoYear BETWEEN DATEADD(m, -35, GETDATE()-day(GETDATE()-1)) AND DATEADD(m, -34, GETDATE()-day (GETDATE()-1))-1 THEN"InvenFiscPerHistTable"."QOH" * "InvenTable"."UnitCost" ELSE NULL END) AS "35"
,SUM (CASE WHEN #CalMoYear BETWEEN DATEADD(m, -34, GETDATE()-day(GETDATE()-1)) AND DATEADD(m, -33, GETDATE()-day (GETDATE()-1))-1 THEN"InvenFiscPerHistTable"."QOH" * "InvenTable"."UnitCost" ELSE NULL END) AS "34"
--and so on until I have 36 months of history up through last month
FROM "InvenTable"
INNER JOIN "SKUTable" ON "InvenTable"."SKUKey" = "SKUTable"."SKUKey"
INNER JOIN "InvenFiscPerHistTable" ON ("InvenTable"."SKUKey" = "InvenFiscPerHistTable"."SKUKey")
AND ("InvenTable"."WarehouseKey" = "InvenFiscPerHistTable"."WarehouseKey")
INNER JOIN "SKUClassTable" "SKUClassTable" ON "SKUTable"."ICKey" = "SKUClassTable"."ICKey"
WHERE "SKUClassTable"."ItemClassName" IN (
'105-03'
,'105-04'
,'105-05'
,'105-06'
,'150-01'
)
I played around a bit with your query and think it can be rewritten and simplified (in my opinion) to the query below. The only thing you need to do is add more items in the pivot part at the end to get more columns.
The logic is that it calculates the difference in months between the first day of the current month and the date that is created from the FiscalYear and FiscalPeriod (according to your rules).
I believe it should work, unless I missed something vital, but without any test data there's of course a fair amount of guess work involved ;-)
Please give it a try and if it doesn't work I'll remove my answer.
I formatted it a bit less compact than it could be to make it easier to follow.
;WITH CTE AS
(
SELECT
SKUKey, WarehouseKey, FiscalPeriod, FiscalYear, QOH,
diff = DATEDIFF
(
month,
CASE WHEN FiscalPeriod IN (1,2,3)
THEN
CAST(FiscalYear + 1 AS CHAR(4))
+ '-' + CAST(FiscalPeriod + 9 AS VARCHAR(2))
+ '-' + CAST(1 AS CHAR(1))
ELSE
CAST(FiscalYear AS CHAR(4))
+ '-' + CAST(FiscalPeriod - 3 AS VARCHAR(2))
+ '-' + CAST(1 AS CHAR(1))
END,
DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
)
FROM InvenFiscPerHistTable
)
SELECT * FROM
(
SELECT diff, QOH * UnitCost as TotalCost
FROM InvenTable i
INNER JOIN SKUTable s ON i.SKUKey = s.SKUKey
INNER JOIN cte ON (i.SKUKey = cte.SKUKey) AND (i.WarehouseKey = cte.WarehouseKey)
INNER JOIN SKUClassTable sc ON s.ICKey = sc.ICKey
WHERE sc.ItemClassName IN ('105-03','105-04','105-05','105-06','150-01')
) A
PIVOT ( SUM(TotalCost) FOR diff IN ([36],[35],[2],[1]) ) p -- add more columns here

Obtaining columns values only if date > today

I have a query where i need to get values in 4 columns but only if the date is greater than today from a 5th column. I have tried the following but it doesn't seem to be working.
Select
(case when clientplans.END_DATE < convert(date,getdate(,101) then '') else insplans.Desc_upper as PLAN NAME,
(case when clientplans.END_DATE < convert(date,getdate(,112) then '') else insplans.ID_NO,
(case when clientplans.END_DATE < convert(date,getdate(,112) then '') else insplans.cert_NO,
I have converted the date on the end date as follows:
convert (varchar,clientplans.END_DATE,112) as POLICY_EXP_DATE,
does it matter that I do the conversion of the end date later in the query? the clientplans.end_date has to be inserted into the results in a certain order which happens to be after the description, id and cert number. Thanks for any help.
Perhaps something like this does what you want:
Select (case when cp.END_DATE > cast(getdate() as date) then insplans.Desc_upper end) as PLAN_NAME,
(case when cp.END_DATE > cast(getdate() as date) then insplans.ID_NO end) as ID_NO,
(case when cp.END_DATE > cast(getdate() as date) then insplans.cert_NO END) as cert_NO
from clientplans cp . . .
Note the following:
This table uses table aliases (cp for clientplans), so the query is easier to write and to read.
It uses cast() to a date to just get the date.
Non-matching rows are given a NULL value instead of ''. That usually makes more sense.
EDIT:
Of course, you can use '', if you like:
Select (case when cp.END_DATE > cast(getdate() as date) then insplans.Desc_upper else '' end) as PLAN_NAME,
(case when cp.END_DATE > cast(getdate() as date) then insplans.ID_NO else '' end) as ID_NO,
(case when cp.END_DATE > cast(getdate() as date) then insplans.cert_NO else '' end) as cert_NO,
(case when cp.END_DATE > cast(getdate() as date)
then convert(varchar(255), cp.StartDate, 121) else ''
end) as StartDate
from clientplans cp . . .
Use this to get the start of today: DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)
For example:
SELECT DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)
And for yours...
Select
(case when clientplans.END_DATE > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) then '') else insplans.Desc_upper as PLAN NAME,
(case when clientplans.END_DATE > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) then '') else insplans.ID_NO,
(case when clientplans.END_DATE > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) then '') else insplans.cert_NO,
i think proper casting is required So I Used Here CAST(Field as DATE) and
in Your Query getdate(,101) is wrong syntax
Select
(case when CAST(clientplans.END_DATE as date) < CAST(getdate() as date) then '')
else insplans.Desc_upper as PLAN NAME,
(case when CAST(clientplans.END_DATE as date) < CAST(getdate() as date) then '')
else insplans.ID_NO,
(case when CAST(clientplans.END_DATE as date) < CAST(getdate() as date) then '')
else insplans.cert_NO
You can use cursor on the 5th column
and check #cursor_date> is greater than today.
Only then will get the rest of the 4 columns.

SQL Time Conversion

I am having trouble with a conversion of time.
I have a table called 'TotalTime' which is set to INT and holds the time in seconds only. I want to convert these seconds to days, hours, minutes, seconds e.g. 01d 09:26:43.
Now I will show you the code I am using:
SELECT [BuildID],[Product],[Program],
SUM(CASE WHEN [State] = 'Running' THEN cast(TotalTime as INT) ELSE 0 END) AS [Running],
SUM(CASE WHEN [State] = 'Break' THEN cast(TotalTime as INT) ELSE 0 END) AS [Break]
FROM [line_log].[dbo].[Line1Log]
GROUP BY [BuildID], [Product], [Program]
So as you can see I am grouping the [State] column and would like to display the results of 'TotalTime' in the format I mentioned above.
Now I have tried this code but it will not work as I cannot convert INT to VARCHAR
SELECT [BuildID],[Product],[Program],
SUM(CASE WHEN [State] = 'Running' THEN CAST(FLOOR(TotalTime / 86400) AS VARCHAR(10))+'d ' + CONVERT(VARCHAR(5), DATEADD(SECOND, TotalTime, '19000101'), 8) ELSE 0 END) AS [Running]
FROM [line_log].[dbo].[Line1Log]
GROUP BY [BuildID], [Product], [Program]
The above would not display it in the exact format I wanted either.
Just wondering if someone would be willing to help me on this one?
Thanks for taking the time to read this :)
You should convert calculated seconds after summing and grouping:
And use VARCHAR(8) instead of VARCHAR(5).
SELECT [BuildID],[Product],[Program],
CAST(FLOOR([Running] / 86400) AS VARCHAR(10))+'d ' + CONVERT(VARCHAR(8), DATEADD(SECOND, [Running], '19000101'), 8) AS [Running],
CAST(FLOOR([Break] / 86400) AS VARCHAR(10))+'d ' + CONVERT(VARCHAR(8), DATEADD(SECOND, [Break], '19000101'), 8) AS [Break]
FROM (
SELECT [BuildID],[Product],[Program],
SUM(CASE WHEN [State] = 'Running' THEN cast(TotalTime as INT) ELSE 0 END) AS [Running],
SUM(CASE WHEN [State] = 'Break' THEN cast(TotalTime as INT) ELSE 0 END) AS [Break]
FROM [line_log].[dbo].[Line1Log]
GROUP BY [BuildID], [Product], [Program]
) T