I want to select the Last 10 Average Weights - sql

Below is my query but when I include my CapturedDateTime and IsOutOfSpec columns then it returns multiple rows but I only want one record to be returned that displays the averages of the last 10 records. So it must return the average PartWeight, average SprueWeight and average Bom Weight for a specified stock code.
--Last 10 Average Report
SELECT Top 10 c.StockCode,i.LongDesc,
AVG(c.PartWeightGram) AS 'Part Weight Average',
AVG(c.SprueWeightGram) AS 'Sprue Weight Average' ,
AVG(c.TolerancePercentage) AS 'Tolerance Average' ,
AVG(c.BomWeightKG * 1000) AS 'Bom Weight Average' ,
AVG(c.PartWeightGram + (c.SprueWeightGram / 2)) - (c.BomWeightKG) AS 'Variance To Syspro Average',
AVG((((((c.PartWeightGram + c.SprueWeightGram / 2))) - (c.BomWeightKG * 1000)) / (c.BomWeightKG * 1000)) * 100) AS 'VarianceToSysproPct'
FROM tblComponentWeightCheck c
LEFT JOIN [Mercury].[EncoreCompanyA].dbo.InvMaster i ON c.StockCode = i.StockCode
WHERE c.StockCode='000-256966-020' And Deleted = 'False'
GROUP BY c.StockCode,i.LongDesc,c.BomWeightKG
ORDER BY c.StockCode DESC
This is my Table:
SELECT [ComponentWeightCheckID]
,[EmpID]
,[StockCode]
,[Process]
,[PartWeightGram]
,[SprueWeightGram]
,[BomWeightKG]
,[TolerancePercentage]
,[AssetID]
,[CapturedDateTime]
,[Hostname]
,[Username]
,[IsOutOfSpec]
,[Tool]
,[Deleted]
FROM [dbo].[tblComponentWeightCheck]
Sample Data:
SELECT Top 10 c.StockCode,i.LongDesc AS 'Description',
(SELECT TOP 10 AVG(PartWeightGram) FROM tblComponentWeightCheck c WHERE c.StockCode = '000-256966-020' GROUP BY c.StockCode ) AS 'Part Weight Average',
(SELECT TOP 10 AVG([SprueWeightGram]) FROM tblComponentWeightCheck c WHERE c.StockCode = '000-256966-020' GROUP BY c.StockCode ) AS 'Sprue Weight Average',
(SELECT TOP 10 AVG(c.TolerancePercentage) FROM tblComponentWeightCheck c WHERE c.StockCode = '000-256966-020' GROUP BY c.StockCode ) AS 'Tolerance Average',
(SELECT TOP 10 AVG([BomWeightKG]) FROM tblComponentWeightCheck c WHERE c.StockCode = '000-256966-020' GROUP BY c.StockCode ) AS 'Bom Weight Average',
(SELECT TOP 10 AVG((c.PartWeightGram + (c.SprueWeightGram / 2)) - (c.BomWeightKG * 1000)) FROM tblComponentWeightCheck c WHERE c.StockCode = '000-256966-020' GROUP BY c.StockCode ) AS 'Variance To Syspro Average',
(SELECT TOP 10 AVG((((((c.PartWeightGram + c.SprueWeightGram / 2))) - (c.BomWeightKG * 1000)) / (c.BomWeightKG * 1000)) * 100) FROM tblComponentWeightCheck c WHERE c.StockCode = '000-256966-020' GROUP BY c.StockCode ) AS 'Variance To Syspro & Average'
FROM tblComponentWeightCheck c
LEFT JOIN [Mercury].[EncoreCompanyA].dbo.InvMaster i ON c.StockCode = i.StockCode
WHERE c.StockCode = '000-256966-020'
AND CONVERT(Date, c.CapturedDateTime) Between '2021-04-01' AND '2021-05-24'
GROUP BY c.StockCode, i.LongDesc
This image shows the result of the above query.It only returns 1 row which it should but it is missing my CapturedDateTime AND IsOutOfSpec columns, as soon as i include those then it returns multiple records which i don't want

Presumably, the LEFT JOIN is not needed -- it would seem odd to have stock codes that are not in the inventory master.
You can do this pretty easily using APPLY:
SELECT Top 10 i.StockCode, i.LongDesc,
AVG(c.PartWeightGram) AS Part_Weight_Average,
AVG(c.SprueWeightGram) AS Sprue_Weight_Average,
AVG(c.TolerancePercentage) AS Tolerance_Average,
AVG(c.BomWeightKG * 1000) AS Bom_Weight_Average,
AVG(c.PartWeightGram + (c.SprueWeightGram / 2)) - (c.BomWeightKG) AS Variance_To_Syspro_Average,
AVG((((((c.PartWeightGram + c.SprueWeightGram / 2))) - (c.BomWeightKG * 1000)) / (c.BomWeightKG * 1000)) * 100) AS VarianceToSysproPct
FROM [Mercury].[EncoreCompanyA].dbo.InvMaster i CROSS APPLY
(SELECT TOP (10) c.*
FROM tblComponentWeightCheck c
WHERE c.StockCode = i.StockCode
ORDER BY c.CapturedDateTime DESC
) c
WHERE i.StockCode = '000-256966-020' AND Deleted = 'False'
GROUP BY i.StockCode, i.LongDesc, c.BomWeightKG
ORDER BY i.StockCode DESC;
For performance, I recommend indexes on tblComponentWeightCheck(StockCode, CapturedDateTime DESC) and InvMaster(StockCode).

Judging by your query, you should use a window function and a subquery instead of top 10. Following an example. However, you will have to provide the sorting criteria for the ROW_NUMBER() in order to define your "TOP 10"...
--Last 10 Average Report
SELECT c.StockCode,c.LongDesc,
AVG(c.PartWeightGram) AS 'Part Weight Average',
AVG(c.SprueWeightGram) AS 'Sprue Weight Average' ,
AVG(c.TolerancePercentage) AS 'Tolerance Average' ,
AVG(c.BomWeightKG * 1000) AS 'Bom Weight Average' ,
AVG(c.PartWeightGram + (c.SprueWeightGram / 2)) - (c.BomWeightKG) AS 'Variance To Syspro Average',
AVG((((((c.PartWeightGram + c.SprueWeightGram / 2))) - (c.BomWeightKG * 1000)) / (c.BomWeightKG * 1000)) * 100) AS 'VarianceToSysproPct'
FROM (
SELECT c.StockCode
,i.LongDesc
,c.PartWeightGram
,c.SprueWeightGram
,c.TolerancePercentage
,c.BomWeightKG
,c.PartWeightGram
,c.PartWeightGram
,ROW_NUMBER() OVER (PARTITION BY c.StockCode ORDER BY ...) AS rn
FROM tblComponentWeightCheck c
LEFT JOIN [Mercury].[EncoreCompanyA].dbo.InvMaster i ON c.StockCode = i.StockCode
WHERE Deleted = 'False'
) c
WHERE c.StockCode='000-256966-020'
AND rn <= 10
GROUP BY c.StockCode,c.LongDesc,c.BomWeightKG
ORDER BY c.StockCode DESC

Related

How can I find median in sql

How can I find median in sql. I am trying
select
date,
sum(amount),
median(amount),
count(user)
from table
group by 1
It shows an error that
function median(double precision) does not exist
Try if this standard sql works.
select
t.[date]
,sum(amount) ttl_amount
,(select sum(s.amount) / (select ((count(*) + 1) % 2) + 1 from #table s where s.[date] = t.[date])
from (select s.amount
from #table s
where t.date = s.date
order by s.amount asc
offset (select ((count(*) - (count(*) + 1) % 2) / 2) from #table s where s.[date] = t.[date]) rows fetch next
(select ((count(*) + 1) % 2) + 1 from #table s where s.[date] = t.[date]) rows only ) s ) median
,count(distinct [user]) dst_user
from #table t
group by [date]

select average of top 3 for each specific sql job

SELECT jobs.Job_ID AS JobID ,
jobs.NAME AS JobName ,
act.start_execution_date AS StartExecutionDate ,
AVG(FLOOR(run_duration / 100)) AS AvgDurationMin ,
CASE
--If job average less than 5 minutes then limit is avg+10 minutes
WHEN AVG(FLOOR(run_duration / 100)) <= 5
THEN ( AVG(FLOOR(run_duration / 100)) ) + 2
--If job average greater than 5 minutes then limit is avg*limit percentage
ELSE ( AVG(FLOOR(run_duration / 100))
)
END AS DurationLimit ,
DATEDIFF(MI, act.start_execution_date, GETDATE()) AS [CurrentDuration]
FROM #currently_running_jobs crj
INNER JOIN msdb..sysjobs AS jobs ON crj.job_id = jobs.job_id
INNER JOIN msdb..sysjobactivity AS act ON act.job_id = crj.job_id
AND act.stop_execution_date IS NULL
AND act.start_execution_date IS NOT NULL
INNER JOIN msdb..sysjobhistory AS hist ON hist.job_id = crj.job_id
AND hist.step_id = 0
WHERE crj.job_state = 1 --and jobs.NAME = 'long_running_testing'
GROUP BY jobs.job_ID ,
jobs.NAME ,
act.start_execution_date ,
DATEDIFF(MI, act.start_execution_date, GETDATE())
HAVING CASE WHEN AVG(FLOOR(run_duration / 100)) <= 5
THEN (AVG(FLOOR(run_duration / 100))) + 2
--THEN ( AVG(FLOOR(run_duration / 100)) ) + 1
ELSE ( AVG(FLOOR(run_duration / 100))
)
END < DATEDIFF(MI, act.start_execution_date, GETDATE())
Can someone please help me to extract the average run_duration of recent three entries of job's partitioned by job_name?
Please find the below script which I used to extract information
of recent three run_duration partitioned by job_name, but it
calculates the average of all run_duration .
Here I need only the recent three run_duration average count.
SELECT top 1 with ties jobs.Job_ID AS JobID , AVG(FLOOR(run_duration/100%100 )),
jobs.NAME AS JobName ,
act.start_execution_date AS StartExecutionDate
from msdb..sysjobs AS jobs
inner join msdb..sysjobactivity AS act ON act.job_id = jobs.job_id
INNER JOIN msdb..sysjobhistory AS hist ON hist.job_id = jobs.job_id AND hist.step_id = 0
GROUP BY jobs.job_ID ,
jobs.NAME
, act.start_execution_date ,hist.run_duration,
DATEDIFF(MI, act.start_execution_date, GETDATE())
order by case when row_number() over (partition by jobs.NAME order by hist.run_duration desc) <= 3 then 0 else 1 end;
Perhaps a CTE would simplify it.
with SeqByJob_cte as ( SELECT jobs.NAME AS JobName
,hist.run_duration
,row_number() over(partition by jobs.NAME order by act.start_execution_date desc) as seq
from msdb..sysjobs AS jobs
inner join msdb..sysjobactivity AS act ON act.job_id = jobs.job_id
INNER JOIN msdb..sysjobhistory AS hist ON hist.job_id = jobs.job_id AND hist.step_id = 0)
select avg(run_duration) as AvgOf3MostRecentRuns
,CASE
--If job average less than 5 minutes then limit is avg+10 minutes
WHEN AVG(FLOOR(run_duration / 100)) <= 5
THEN ( AVG(FLOOR(run_duration / 100)) ) + 2
--If job average greater than 5 minutes then limit is avg*limit percentage
ELSE ( AVG(FLOOR(run_duration / 100))
)
END AS DurationLimit
,JobName
from SeqByJob_cte
where seq <= 3
group by JobName

Query to find long running jobs in SQL server

select
j.name as 'JobName',
run_date,
run_time,
msdb.dbo.agent_datetime(run_date, run_time) as 'RunDateTime',
h.run_duration,
((run_duration/10000*3600 + (run_duration/100)%100*60 + run_duration%100 + 31 ) / 60)
as 'RunDurationMinutes'
From msdb.dbo.sysjobs j
INNER JOIN msdb.dbo.sysjobhistory h
ON j.job_id = h.job_id
where j.enabled = 1
AND
((run_duration/10000*3600 + (run_duration/100)%100*60 + run_duration%100 + 31 ) / 60) > 1
The above SQL query will fetch list of a all jobs that takes more then a minute.
But it give a huge list, i dont want that all.
I just want last 2 run of every jobs.
I tried using top 2 and order by desc but it does not list all the jobs in the list.
I just want last 2 run of every job.
Any suggestions.?
Look at ROW_NUMER() ranging function:
select * from (
select
j.name as 'JobName',
run_date,
run_time,
msdb.dbo.agent_datetime(run_date, run_time) as 'RunDateTime',
h.run_duration,
((run_duration/10000*3600 + (run_duration/100)%100*60 + run_duration%100 + 31 ) / 60)
as 'RunDurationMinutes',
ROW_NUMBER() OVER(PARTITION BY j.name ORDER BY msdb.dbo.agent_datetime(run_date, run_time) DESC) NROW
From msdb.dbo.sysjobs j
INNER JOIN msdb.dbo.sysjobhistory h
ON j.job_id = h.job_id
where j.enabled = 1
AND
((run_duration/10000*3600 + (run_duration/100)%100*60 + run_duration%100 + 31 ) / 60) > 1
) t where nrow < 3
To make things clear I have done:
Add new column to your query:
ROW_NUMBER() OVER(PARTITION BY j.name ORDER BY msdb.dbo.agent_datetime(run_date, run_time) DESC) NROW
This column group by all the records by j.name field and number each group by 'RunDateTime' field.
Now we need to get all the records where NROW == 1 or NROW == 2. I have created subquery (not sure it is a best solution) and and WHERE condition
select * from ( ... ) t where nrow < 3
Try this
SELECT
r.session_id, r.start_time,
TotalElapsedTime_ms = r.total_elapsed_time
, r.[status]
, r.command
, DatabaseName = DB_Name(r.database_id)
, r.wait_type
, r.last_wait_type
, r.wait_resource
, r.cpu_time
, r.reads
, r.writes
, r.logical_reads
, t.[text] AS [executing batch]
, SUBSTRING(
t.[text], r.statement_start_offset / 2,
( CASE WHEN r.statement_end_offset = -1 THEN DATALENGTH (t.[text])
ELSE r.statement_end_offset
END - r.statement_start_offset ) / 2
) AS [executing statement]
, p.query_plan
FROM
sys.dm_exec_requests r
CROSS APPLY
sys.dm_exec_sql_text(r.sql_handle) AS t
CROSS APPLY
sys.dm_exec_query_plan(r.plan_handle) AS p
ORDER BY
r.total_elapsed_time DESC;

merge and refine two query results sql server

i have two query please tell me how to merge these two queries and also how to refine these query.Merge query on base on GroupID.
(SELECT count(idlee.ObjectId) AS 'Count', idlee.GroupId, idlee.Name
FROM (SELECT CONVERT(int, Sum(idle.distance)) AS distance, idle.ObjectId, idle.GroupId, idle.Name
FROM (SELECT Message.ObjectId, fn_GpsUtil_Distance(Message.x, Message.y, lead(Message.x)
OVER (partition BY Message.objectid
ORDER BY Message.GpsTime), lead(Message.y) OVER (partition BY Message.objectid
ORDER BY Message.GpsTime)) AS distance, [Group].GroupId, [Group].Name
FROM [Group] INNER JOIN
GroupObject ON [Group].GroupId = GroupObject.GroupId INNER JOIN
Message ON GroupObject.ObjectId = Message.ObjectId INNER JOIN
Object ON GroupObject.ObjectId = Object.ObjectId
WHERE (Object.Enabled = 1) AND (Object.ClientId = 5) AND (Message.GpsTime >= GETDATE() - 1) AND
(Message.GpsTime <= GETDATE())) AS idle
GROUP BY idle.ObjectId, idle.GroupId, idle.Name) AS idlee
WHERE idlee.distance < 10
GROUP BY idlee.GroupId, idlee.Name)
output
Count GroupID Group
36 15 DC-1
30 16 DC-2
13 17 DC-3
64 13 LC-1
16 14 LC-2
second query which i use to retrieve data
(SELECT count(idlee.ObjectId) AS 'Count', idlee.GroupId, idlee.Name
FROM (SELECT CONVERT(int, Sum(idle.distance)) AS distance, idle.ObjectId, idle.GroupId, idle.Name
FROM (SELECT Message.ObjectId, fn_GpsUtil_Distance(Message.x, Message.y, lead(Message.x)
OVER (partition BY Message.objectid
ORDER BY Message.GpsTime), lead(Message.y) OVER (partition BY Message.objectid
ORDER BY Message.GpsTime)) AS distance, [Group].GroupId, [Group].Name
FROM [Group] INNER JOIN
GroupObject ON [Group].GroupId = GroupObject.GroupId INNER JOIN
Message ON GroupObject.ObjectId = Message.ObjectId INNER JOIN
Object ON GroupObject.ObjectId = Object.ObjectId
WHERE (Object.Enabled = 1) AND (Object.ClientId = 5) AND (Message.GpsTime >= GETDATE() - 1) AND
(Message.GpsTime <= GETDATE())) AS idle
GROUP BY idle.ObjectId, idle.GroupId, idle.Name) AS idlee
WHERE idlee.distance >= 100 AND idlee.distance <= 300
GROUP BY idlee.GroupId, idlee.Name)
Count GroupID Group
40 15 DC-1
50 16 DC-2
20 17 DC-3
64 13 LC-1
16 14 LC-2
but i want output like this on Group base.
GroupID Group Count 0<10 Count 100 To 300
15 DC-1 36 40
16 DC-2 30 50
17 DC-3 13 20
13 LC-1 64 64
14 LC-2 16 16
Try this...join the SQLs with UNION, in the first one count(idlee.ObjectId) AS count1, 0 as count2 and in the second one 0 as count1, count(idlee.ObjectId) AS count2.
Then enclose the entire SQL as a temp table and sum Count1 and Count2.
SELECT Temp.GroupID, Temp.Group, Sum(Temp.Count1) as CountLess10, Sum(Temp.Count2) as Count100300 FROM
(
(SELECT count(idlee.ObjectId) AS count1, 0 as count2, idlee.GroupId as GroupID, idlee.Name as Group
FROM (SELECT CONVERT(int, Sum(idle.distance)) AS distance, idle.ObjectId, idle.GroupId, idle.Name
FROM (SELECT Message.ObjectId, fn_GpsUtil_Distance(Message.x, Message.y, lead(Message.x)
OVER (partition BY Message.objectid
ORDER BY Message.GpsTime), lead(Message.y) OVER (partition BY Message.objectid
ORDER BY Message.GpsTime)) AS distance, [Group].GroupId, [Group].Name
FROM [Group] INNER JOIN
GroupObject ON [Group].GroupId = GroupObject.GroupId INNER JOIN
Message ON GroupObject.ObjectId = Message.ObjectId INNER JOIN
Object ON GroupObject.ObjectId = Object.ObjectId
WHERE (Object.Enabled = 1) AND (Object.ClientId = 5) AND (Message.GpsTime >= GETDATE() - 1) AND
(Message.GpsTime <= GETDATE())) AS idle
GROUP BY idle.ObjectId, idle.GroupId, idle.Name) AS idlee
WHERE idlee.distance < 10
GROUP BY idlee.GroupId, idlee.Name)
UNION
(SELECT 0 as count1, count(idlee.ObjectId) AS count2, idlee.GroupId as GroupID, idlee.Name as Name
FROM (SELECT CONVERT(int, Sum(idle.distance)) AS distance, idle.ObjectId, idle.GroupId, idle.Name
FROM (SELECT Message.ObjectId, fn_GpsUtil_Distance(Message.x, Message.y, lead(Message.x)
OVER (partition BY Message.objectid
ORDER BY Message.GpsTime), lead(Message.y) OVER (partition BY Message.objectid
ORDER BY Message.GpsTime)) AS distance, [Group].GroupId, [Group].Name
FROM [Group] INNER JOIN
GroupObject ON [Group].GroupId = GroupObject.GroupId INNER JOIN
Message ON GroupObject.ObjectId = Message.ObjectId INNER JOIN
Object ON GroupObject.ObjectId = Object.ObjectId
WHERE (Object.Enabled = 1) AND (Object.ClientId = 5) AND (Message.GpsTime >= GETDATE() - 1) AND
(Message.GpsTime <= GETDATE())) AS idle
GROUP BY idle.ObjectId, idle.GroupId, idle.Name) AS idlee
WHERE idlee.distance >= 100 AND idlee.distance <= 300
GROUP BY idlee.GroupId, idlee.Name)
) Temp Group By Temp.GroupID, Temp.Group
Hope this helps.

Calulating percentage table column in SQL

How can I calculate the percentage of a whole column? Currently what I've written so far only gives me the percentage of each row. I want only 1 row with the total percentage. I want to sum all the values to calculate one percentage.
SELECT TOP 1000
CONVERT(DECIMAL(10, 2), CAST(Passed AS DECIMAL(10, 2))
/ ( Actual ) * 100) AS Percent
FROM Audits
WHERE
MONTH(TransActionDate) = MONTH(GETDATE())
GROUP BY Actual
, Passed
, transactiondate
ORDER BY TransActionDate DESC
Try using AVG() and remove the fields from the GROUP BY clause:
SELECT AVG(CONVERT(DECIMAL(10, 2), CAST(Passed AS DECIMAL(10, 2))
/ ( Actual ) * 100)) AS Percent
FROM Audits
WHERE MONTH(TransActionDate) = MONTH(GETDATE())
If you need TOP 1000, then use a subquery:
SELECT AVG(Percent)
FROM (
SELECT TOP 1000
CONVERT(DECIMAL(10, 2), CAST(Passed AS DECIMAL(10, 2))
/ ( Actual ) * 100) AS Percent
FROM Audits
WHERE MONTH(TransActionDate) = MONTH(GETDATE())
ORDER BY TransActionDate DESC
) t