How to improve this sql query - sql

Here I get the "ProcessTime" in hours and minutes, but in case of seconds only I check for the opposite condition (see code below)
Is there any way to improve that?
select convert(varchar(10),ScanDate,101) as [Date], tmb.WO, tc.WOCategory, count(IdSingle) QtyProd, tb.Brand, tm.Model,
(case when (DateDiff(mi, Min(convert(varchar(10),ScanDate,8)), Max(convert(varchar(10),ScanDate,8)))/60%24 > 0) then
convert(varchar(5), DateDiff(mi, Min(convert(varchar(10),ScanDate,8)), Max(convert(varchar(10),ScanDate,8)))/60%24) + 'h '
else
''
end) +
(case when (DateDiff(mi, Min(convert(varchar(10),ScanDate,8)), Max(convert(varchar(10),ScanDate,8)))%60 > 0) then
convert(varchar(5), DateDiff(mi, Min(convert(varchar(10),ScanDate,8)), Max(convert(varchar(10),ScanDate,8)))%60) + 'm'
else
''
end) +
(case when
(DateDiff(mi, Min(convert(varchar(10),ScanDate,8)), Max(convert(varchar(10),ScanDate,8)))/60%24 <= 0) and
(DateDiff(mi, Min(convert(varchar(10),ScanDate,8)), Max(convert(varchar(10),ScanDate,8)))%60 <= 0) then
'< 1 min'
else
''
end) ProcessTime

With SQL Server 2005 you can use a CTE to improve this query.
Something like this:
;WITH minmax AS
(
SELECT someKey,
DateDiff(mi, Min(convert(varchar(10),ScanDate,8)), Max(convert(varchar(10),ScanDate,8))) as mdiff
FROM tablename
GROUP BY fieldName
)
Select convert(varchar(10),ScanDate,101) as [Date], tmb.WO, tc.WOCategory, count(IdSingle) QtyProd, tb.Brand, tm.Model,
(case when (mdiff/60%24 > 0) then
convert(varchar(5), mdiff/60%24) + 'h '
else
''
end) +
(case when (mdiff%60 > 0) then
convert(varchar(5), mdiff%60) + 'm'
else
''
end) +
(case when
(DateDiff(mi, mdiff/60%24 <= 0) and (DateDiff(mi, mdiff%60 <= 0) then
'< 1 min'
else
''
end) ProcessTime
from tablename
join minmax on tablename.somekey = minmax.somekey

Related

simplify a SQL case statement in a case expression

How would I simplify this case statement in T-SQL? It provides the desired result, but it's very unwieldy and hard to read. I have to use the inner case statement to convert a Julian date (aka 6 digit number) into a regular date format.
Basically i'm doing a datediff( getdate(), case statement). Getdate() just returns the time now (ie. 2/27/2020) and the case statement converts a julian date (ie. 123456) into a normal date (ie, 1/1/2020).
Here's the expect output if the query was ran today on Feb 27.
Select CASE
WHEN Datediff(day, Getdate(), CASE
WHEN a.wadpl = 0
THEN NULL
ELSE Dateadd(d, Substring(Cast(wadpl AS VARCHAR(6)), 4, 3) - 1, CONVERT(DATETIME, CASE
WHEN LEFT(Cast(wadpl AS VARCHAR(6)), 1) = '1'
THEN '20'
ELSE '21'
END + Substring(Cast(wadpl AS VARCHAR(6)), 2, 2) + '-01-01'))
END) < 0
THEN 'Overdue Now'
WHEN Datediff(day, Getdate(), CASE
WHEN a.wadpl = 0
THEN NULL
ELSE Dateadd(d, Substring(Cast(wadpl AS VARCHAR(6)), 4, 3) - 1, CONVERT(DATETIME, CASE
WHEN LEFT(Cast(wadpl AS VARCHAR(6)), 1) = '1'
THEN '20'
ELSE '21'
END + Substring(Cast(wadpl AS VARCHAR(6)), 2, 2) + '-01-01'))
END) <= 30
THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM Table_X
Here is a easy one to understand, assuming a.wadpl is an integer:
SELECT CASE
WHEN DATEDIFF(DAY, GETDATE(), DATEADD(DAY, a.wadpl % 1000, DATEADD(YEAR,a.wadpl / 1000,'1899-12-31'))) <0 THEN 'Overdue now'
WHEN DATEDIFF(DAY, GETDATE(), DATEADD(DAY, a.wadpl % 1000, DATEADD(YEAR,a.wadpl / 1000,'1899-12-31'))) <= 30 THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM Table_X
or you can simplify by using a subquery (or you can use a WITH):
SELECT CASE
WHEN Age <0 THEN 'Overdue now'
WHEN Age <= 30 THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM (
SELECT DATEDIFF(DAY,GETDATE(),
DATEADD(DAY,wadpl%1000,DATEADD(YEAR,wadpl/1000,'1899-12-31'))) Age, *
FROM Table_X) a
This will of course cause you to do this arithmetic for each row, and you can't easily use any indexes. If you were asking about aggregates, then I would suggest doing the opposite, and pre-calculating the dates and use those in your query instead. You might also want to consider putting a persisted computed column on table_x:
ALTER TABLE TABLE_X
ADD wadpl_dt AS
(DATEADD(DAY,wadpl%1000,DATEADD(YEAR,wadpl/1000,'1899-12-31'))) PERSISTED;
Now you can just refer to table_x.wadpl_dt whenever you want the datetime, and your query would become:
SELECT CASE
WHEN Age <0 THEN 'Overdue now'
WHEN Age <= 30 THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM (
SELECT DATEDIFF(DAY,GETDATE(), wadpl_dt) Age, *
FROM Table_X) a
Here is the easy way to convert a date to what you refer to as the julian date:
SELECT (DATEPART(YEAR,GETDATE())-1900) * 1000 + DATEPART(DAYOFYEAR, GETDATE())
And this is how you can use it:
DECLARE #overdue int;
DECLARE #next30 int;
SET #overdue = (SELECT (DATEPART(YEAR,GETDATE())-1900) * 1000 + DATEPART(DAYOFYEAR, GETDATE()));
SET #next30 = (SELECT (DATEPART(YEAR,GETDATE()+30)-1900) * 1000 + DATEPART(DAYOFYEAR, GETDATE()+30));
SELECT CASE
WHEN wadpl < #overdue THEN 'Overdue now'
WHEN wadpl <= #next30 THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM Table_X

joining select statements?

I would like to do a inner join in my query but I don´t know how to summarize my two select statements into one query.
This is the first query:
select
Machine
, EventDefinition
, Duration
, sum(Duration) over (partition by 1) As Total
, Duration/sum(Duration) over (partition by 1)*100 AS Distribution
,case when EventCategory < 0.05 Then 'NOT INCL' ELSE 'OK' END AS Under3Min
from (
Select
SystemName AS Machine
, EventDefinition
, EventDate
, EventStartDateTime
, IsNull(EventEndDateTime, GETDATE()) as EventEndDateTime
, Sum(cast(EventEndDateTime - EventStartDateTime as float))*24 as Duration
,Sum(case when CustomEvent = 'without Stop' then cast(EventEndDateTime - EventStartDateTime as float)*24 else 0 end) as EventCategory
FROM tDataCategory
WHERE EventDate >= #StartDateTime
AND EventDate <= #EndDateTime
AND SystemName = '201'
Group BY SystemName, eventdefinition, eventstartdatetime, eventenddatetime, EventDefinition, EventDate, CustomEvent
) as t
WHERE CustomEvent <> 'without Stop'
OR (CustomEvent = 'without Stop' AND t.EventCategory >=0.05)
group by EventDefinition
, Duration
,Machine
,EventCategory
output:
and my second query:
SELECT DataValue = case when Prod = 0 then 0 else ISNULL(100.0 / Prod * Scrap, 0) end,
Value = GoodUnits/TheoreticalUnits *100,
FROM (
Select intervaldate as DateValue, intervalDateWeek as Datum, tsystem.Name as Name, ProductName as Product, teamname as Team,
SUM(case when IssueName in ('A1', 'A2') then calculationUnitsInitial else 0 end) as Scrap,
Sum(case when IssueName = 'Prod' then calculationUnitsInitial else 0 end) as Prod,
SUM(GoodUnits)
As GoodUnits,
SUM(TheoreticalUnits) As TheoreticalUnits,
from tCount inner join tsystem ON tCount.systemid = tsystem.id
where IntervalDate >= dateadd(wk, datediff(wk, 1, getdate()), 0)
and IntervalDate <= dateadd(wk, datediff(wk, 0, getdate()), 0)
AND ((DATEPART(dw, IntervalDate) + ##DATEFIRST) % 7) NOT IN (0,1)
and tsystem.Name = '201'
group by intervaldate, tsystem.Name, intervaldateweek, ProductName, teamname
) as s
output:
I tried it to add in my query two select statements. But if I do this the output is wrong. I really don´t know how I should join this two queries.
I would like to do then this calculation: Distribution * (1 - Value)
Distribution from the first query and Value from the second query
I assume the first and second result set has to be joined based on A.Machine=B.Name
Try like this,
SELECT A.Distribution * (1 - B.Value)
FROM (
SELECT Machine
,EventDefinition
,Duration
,sum(Duration) OVER (PARTITION BY 1) AS Total
,Duration / sum(Duration) OVER (PARTITION BY 1) * 100 AS Distribution
,CASE
WHEN EventCategory < 0.05
THEN 'NOT INCL'
ELSE 'OK'
END AS Under3Min
FROM (
SELECT SystemName AS Machine
,EventDefinition
,EventDate
,EventStartDateTime
,IsNull(EventEndDateTime, GETDATE()) AS EventEndDateTime
,Sum(cast(EventEndDateTime - EventStartDateTime AS FLOAT)) * 24 AS Duration
,Sum(CASE
WHEN CustomEvent = 'without Stop'
THEN cast(EventEndDateTime - EventStartDateTime AS FLOAT) * 24
ELSE 0
END) AS EventCategory
FROM tDataCategory
WHERE EventDate >= #StartDateTime
AND EventDate <= #EndDateTime
AND SystemName = '201'
GROUP BY SystemName
,eventdefinition
,eventstartdatetime
,eventenddatetime
,EventDefinition
,EventDate
,CustomEvent
) AS t
WHERE CustomEvent <> 'without Stop'
OR (
CustomEvent = 'without Stop'
AND t.EventCategory >= 0.05
)
GROUP BY EventDefinition
,Duration
,Machine
,EventCategory
) A
INNER JOIN (
SELECT DataValue = CASE
WHEN Prod = 0
THEN 0
ELSE ISNULL(100.0 / Prod * Scrap, 0)
END
,Value = GoodUnits / TheoreticalUnits * 100
,NAME
FROM (
SELECT intervaldate AS DateValue
,intervalDateWeek AS Datum
,tsystem.NAME AS NAME
,ProductName AS Product
,teamname AS Team
,SUM(CASE
WHEN IssueName IN (
'A1'
,'A2'
)
THEN calculationUnitsInitial
ELSE 0
END) AS Scrap
,Sum(CASE
WHEN IssueName = 'Prod'
THEN calculationUnitsInitial
ELSE 0
END) AS Prod
,SUM(GoodUnits) AS GoodUnits
,SUM(TheoreticalUnits) AS TheoreticalUnits
,
FROM tCount
INNER JOIN tsystem ON tCount.systemid = tsystem.id
WHERE IntervalDate >= dateadd(wk, datediff(wk, 1, getdate()), 0)
AND IntervalDate <= dateadd(wk, datediff(wk, 0, getdate()), 0)
AND ((DATEPART(dw, IntervalDate) + ##DATEFIRST) % 7) NOT IN (
0
,1
)
AND tsystem.NAME = '201'
GROUP BY intervaldate
,tsystem.NAME
,intervaldateweek
,ProductName
,teamname
) AS s
) B ON A.Machine = B.NAME

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

SQL - How to find currently running job steps through TSQL

I am writing a query to find currently running job in SQL (I know we can view it in Job Active Monitor, but I've a need to do in TSQL). Though I can query sysjobactivity table to find currently running job, it's nowhere telling what job step is running (because my job might have more than 1 step).
Query I used:
SELECT s.name AS [JOB_NAME],
'' AS [STEP_ID],
'' AS STEP_NAME,
'Processing' AS STATUS,
sja.run_requested_date AS START_TIME,
null AS END_DATE,
convert(varchar, (getdate() - sja.run_requested_date), 8) AS Duration
FROM sysjobactivity sja, sysjobs s
WHERE sja.job_id = s.job_id
AND sja.run_requested_date > getdate() - 1
AND sja.stop_execution_date IS NULL
Please help me finding the step ID & Step name in which the job is currently progressing.
I think below script help to get SQL Jobs with current execution step, try this
msdb.dbo.sp_help_job #execution_status = 1
DECLARE #StepCount INT
SELECT #StepCount = COUNT(1)
FROM msdb.dbo.sysjobsteps
WHERE job_id = '0523333-5C24-1526-8391-AA84749345666' --JobID
SELECT
[JobName]
,[JobStepID]
,[JobStepName]
,[JobStepStatus]
,[RunDateTime]
,[RunDuration]
FROM
(
SELECT
j.[name] AS [JobName]
,Jh.[step_id] AS [JobStepID]
,jh.[step_name] AS [JobStepName]
,CASE
WHEN jh.[run_status] = 0 THEN 'Failed'
WHEN jh.[run_status] = 1 THEN 'Succeeded'
WHEN jh.[run_status] = 2 THEN 'Retry (step only)'
WHEN jh.[run_status] = 3 THEN 'Canceled'
WHEN jh.[run_status] = 4 THEN 'In-progress message'
WHEN jh.[run_status] = 5 THEN 'Unknown'
ELSE 'N/A'
END AS [JobStepStatus]
,msdb.dbo.agent_datetime(run_date, run_time) AS [RunDateTime]
,CAST(jh.[run_duration]/10000 AS VARCHAR) + ':' + CAST(jh.[run_duration]/100%100 AS VARCHAR) + ':' + CAST(jh.[run_duration]%100 AS VARCHAR) AS [RunDuration]
,ROW_NUMBER() OVER
(
PARTITION BY jh.[run_date]
ORDER BY jh.[run_date] DESC, jh.[run_time] DESC
) AS [RowNumber]
FROM
msdb.[dbo].[sysjobhistory] jh
INNER JOIN msdb.[dbo].[sysjobs] j
ON jh.[job_id] = j.[job_id]
WHERE
j.[name] = 'ProcessCubes' --Job Name
AND jh.[step_id] > 0
AND CAST(RTRIM(run_date) AS DATE) = CAST(GETDATE() AS DATE) --Current Date
) A
WHERE
[RowNumber] <= #StepCount
AND [JobStepStatus] = 'Failed'
Try this:
SELECT distinct
cast([sJOB].[job_id] as varchar(max)) AS execution_id
, [sJSTP].[step_name] AS executable_name
, [sJOB].[name] AS package_name
, CASE [sJSTP].[run_date]
WHEN 0 THEN NULL
ELSE
CAST(
CAST([sJSTP].[run_date] AS CHAR(8))
+ ' '
+ STUFF(
STUFF(RIGHT('000000' + CAST([sJSTP].[run_time] AS VARCHAR(6)), 6)
, 3, 0, ':')
, 6, 0, ':')
AS DATETIME)
END AS start_time,
dateadd(ss, run_duration, CASE [sJSTP].[run_date]
WHEN 0 THEN NULL
ELSE
CAST(
CAST([sJSTP].[run_date] AS CHAR(8))
+ ' '
+ STUFF(
STUFF(RIGHT('000000' + CAST([sJSTP].[run_time] AS VARCHAR(6)), 6)
, 3, 0, ':')
, 6, 0, ':')
AS DATETIME)
END) end_time
-- , [sJSTP].[run_duration] [looptijd in minuten]
, CASE [sJSTP].[run_status]
WHEN 0 THEN 'Failed'
WHEN 1 THEN 'Success'
WHEN 2 THEN 'Retry'
WHEN 3 THEN 'Cancelled'
WHEN 5 THEN 'Unknown'
END AS execution_result_description
FROM
[msdb].[dbo].[sysjobhistory] AS [sJSTP]
INNER JOIN [msdb].[dbo].[sysjobs] AS [sJOB]
ON [sJSTP].[job_id] = [sJOB].[job_id]
inner join [msdb].[dbo].[sysjobsteps] steps
ON [sJSTP].[job_id] = [steps].[job_id]
where [sJSTP].[run_date] <> 0
and CASE [sJSTP].[run_date]
WHEN 0 THEN NULL
ELSE
CAST(
CAST([sJSTP].[run_date] AS CHAR(8))
+ ' '
+ STUFF(
STUFF(RIGHT('000000' + CAST([sJSTP].[run_time] AS VARCHAR(6)), 6)
, 3, 0, ':')
, 6, 0, ':')
AS DATETIME)
END between dateadd(hh, -20, getdate()) and getdate()
and [sJSTP].[step_name] not in ('(Job outcome)')
order by start_time desc
Additionally I use this query to see step result from a running SSIS job. However, this only shows you the finished steps, not the running ones. I still have to find an SQL to see the currently running step and merge it with this one.
select distinct
cast(e.execution_id as varchar(max)),
e.executable_name,
e.package_name,
CONVERT(datetime, es.start_time) AS start_time
, CONVERT(datetime, es.end_time) AS end_time
, datediff(mi, es.start_time, es.end_time) [running time]
, case es.execution_result
when 0 then 'Success'
when 1 then 'Failed'
when 2 then 'Completion'
when 3 then 'Cancelled'
else cast(es.execution_result as varchar(max)) end as execution_result_description
from ssisdb.catalog.executables e
left join ssisdb.catalog.executable_statistics es
on e.executable_id = es.executable_id
and e.execution_id = es.execution_id
order by 6 desc