Filter rows by specific interval - sql-server

I have the following DateTime values in a table, I need to filter the set only if there was a gap between this value > 5 seconds. This should be for a specific date, starting with the first row.
Any idea how to do it only in SQL using SQL Server 2012?
1 2014-04-02 05:33:56.60
2 2014-04-02 05:40:01.55
3 2014-04-02 05:52:45.81
4 2014-04-02 05:52:47.50
5 2014-04-02 06:35:48.84
6 2014-04-02 06:50:49.72
7 2014-04-02 07:01:02.71
8 2014-04-02 07:01:04.35
9 2014-04-02 07:01:09.29
10 2014-04-02 07:44:05.71
11 2014-04-02 08:37:47.06

In SQL Server 2012 you can use lead function, Try following
;with cte as
(
select id, d, datediff(s, d, lead(d) over(order by d)) as diff from Test
)
select * from cte where diff > 5

you can use it like this
WITH rows AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY InputDate) AS rn
FROM given_table
)
SELECT DATEDIFF(second, mc.InputDate, mp.InputDate)
FROM rows mc
JOIN rows mp
ON mc.rn = mp.rn - 1
where DATEDIFF(second, mc.InputDate, mp.InputDate)> 5

You can use the lead function to get the next date and datediff to calculate the seconds difference, then filter for your criteria.
with cte as
(
select id, date, diff = datediff(s, date, lead(date) over(order by date)
from tbl
)
select * from cte where diff > 5

Hope this will also help you.
DECLARE #TAB TABLE (ID INT,DT DATETIME)
INSERT INTO #TAB VALUES
(1 ,'2014-04-02 05:33:56.60'),
(2 ,'2014-04-02 05:40:01.55'),
(3 ,'2014-04-02 05:52:45.81'),
(4 ,'2014-04-02 05:52:47.50'),
(5 ,'2014-04-02 06:35:48.84'),
(6 ,'2014-04-02 06:50:49.72'),
(7 ,'2014-04-02 07:01:02.71'),
(8 ,'2014-04-02 07:01:04.35'),
(9 ,'2014-04-02 07:01:09.29'),
(10,'2014-04-02 07:44:05.71'),
(11,'2014-04-02 08:37:47.06')
--Query
SELECT A.*,B.*
FROM #TAB A,#TAB B
WHERE A.ID = B.ID - 1
AND DATEDIFF(SECOND,A.DT,B.DT) > 5
--Result

Related

How to insert missing years in temporary table in MS SQL Server

I work with Sales and problem is that this table does not have records for each client for every year. Records are missing randomly. Instead i need to have those years there and put 0 for sales for those years for my analysis.
I have limited knowledge of SQL. Can anybody help on this one? What i have as of now and what i would like to have is shown below.
I have thoughts to use LAG() function, but missing records can be for 2 years in a row or 3. I am not sure how to tackle such problem.
What I have now:
Client_ID
SalesYear
Sales
1
2010
12
1
2012
20
1
2013
21
1
2016
14
What i need to have:
Client_ID
SalesYear
Sales
1
2010
12
1
2011
0
1
2012
20
1
2013
21
1
2014
0
1
2015
0
1
2016
14
You need a complete list of years to outer-join with.
You can do this a number of ways, the basic principle would be:
with y as (
select * from (values(2010),(2011),(2012),(2013),(2014),(2015),(2016))y(y)
)
insert into t (Client_Id, SalesYear, Sales)
select 1, y.y, 0
from y
where not exists (select * from t where t.SalesYear = y.y);
Something like this might help:
DECLARE #Sales TABLE
(Client_ID int, SalesYear int, Sales money)
INSERT INTO #Sales(Client_ID, SalesYear, Sales) SELECT 1, 2010, 12
INSERT INTO #Sales(Client_ID, SalesYear, Sales) SELECT 1, 2012, 20
INSERT INTO #Sales(Client_ID, SalesYear, Sales) SELECT 1, 2013, 21
INSERT INTO #Sales(Client_ID, SalesYear, Sales) SELECT 1, 2016, 14;
with years as
(
select 2000 as theYear
UNION ALL
select y.theYear + 1 as theYear
from years y
where y.theYear + 1 <= YEAR(GetDate())
)
select
Y.theYear, S.Client_ID, S.Sales
FROM
Years Y
LEFT JOIN
#Sales S ON S.SalesYear = Y.theYear
option (maxrecursion 0)
You can change "2000" to something more appropriate.

Finding the 2 rows where a given value sits between 2 values in a table

I need to find 2 values and related columns where a given number either sits between the column values or is either of the 2 values. Really confusing but here is a table:
I have a car_id 2 which is going at speed 12 and I want to get a fuel value. I need to get the value of the next higher and the next lower and use those to calculate the fuel for speed 12 for car_id 2. ids are not in any useful order and speed is not always incremental. I have a stored procedure which passes the values of car_id and speed and delivers the value after a calculation but I would like to just use a query or build a view which can perform this function too.
id
car_id
speed
fuel
1
1
5
10
2
1
10
20
3
1
15
29
4
1
20
37
5
1
25
45
6
2
5
7
7
2
10
14
8
2
15
20
9
2
20
26
10
2
25
31
Hope I haven't confused you too much and thank you for your help.
DROP TABLE IF EXISTS #data;
CREATE TABLE #data
(
id INT,
car_id INT,
speed INT,
fuel INT
);
INSERT INTO #data
VALUES
(1 ,1, 5 ,10),
(2 ,1, 10 ,20),
(3 ,1, 15 ,29),
(4 ,1, 20 ,37),
(5 ,1, 25 ,45),
(6 ,2, 5 , 7),
(7 ,2, 10 ,14),
(8 ,2, 15 ,20),
(9 ,2, 20 ,26),
(10 ,2, 25 ,31);
DECLARE #speed INT = 12;
DECLARE #car_id INT = 2;
WITH cte AS (
SELECT speed,
fuel,
LEAD(speed,1) OVER (PARTITION BY car_id ORDER BY speed) speed2,
LEAD(fuel,1) OVER (PARTITION BY car_id ORDER BY speed) fuel2,
ROW_NUMBER() OVER (PARTITION BY car_id ORDER BY speed) rn
FROM #data
WHERE car_id = #car_id
), rts AS
(
SELECT MAX(rn) rowtoselect
FROM cte
WHERE cte.speed <= #speed
)
SELECT cte.speed, cte.fuel, cte.speed2, cte.fuel2
FROM cte
INNER JOIN rts ON cte.rn = rts.rowtoselect
select * from car_data
DECLARE #speed INT = 12;
DECLARE #car_id INT = 2;
with cte as
(
select * from car_data
union all
select #car_id,#speed,null
)
select car_id,speed,y1+(y2-y1)*(speed-x1)/(x2-x1) as fuel from
( select *,lead(speed,1) over(partition by car_id order by speed) as x1,lag(speed,1) over(partition by car_id order by speed) as x2,
lead(fuel,1) over(partition by car_id order by speed) as y1, lag(fuel,1) over(partition by car_id order by speed) as y2
from cte) tab
where speed=#speed and car_id=#car_id

Accumulative Update for previous records

I have table that shows these information
Month NewClients OnHoldClients
5-2017 10 2
6-2017 16 4
7-2017 11 1
8-2017 15 6
9-2017 18 7
I am trying to find the accumulative total for each month
which is
(NewClients - OnHoldClients) + Previous Month Total
Something like this
Month NewClients OnHoldClients Total
5-2017 10 2 8
6-2017 16 4 20
7-2017 11 1 30
8-2017 15 6 39
9-2017 18 7 50
the query i tried to build was something like this but I think should be an easier way to do that
UPDATE MyTable
SET Total = (SELECT TOP 1 Total FROM MyTable B WHERE B.Month < A.Month) + NewClients - OnHoldClients
FROM MyTable A
Before we begin, note the mere fact that you're facing such calculative problem is a symptom that maybe you don't have the best possible design. Normally for this purpose calculated values are being stored along the way as the records are inserted. So i'd say you'd better have a total field to begin with and calculate it as records amass.
Now let's get down to the problem at hand. i composed a query which does that nicely but it's a bit verbose due to recursive nature of the problem. However, it yields the exact expected result:
DECLARE #dmin AS date = (SELECT min(mt.[Month]) from dbo.MyTable mt);
;WITH cte(_Month, _Total) AS (
SELECT mt.[Month] AS _Month, (mt.NewClients - mt.OnHoldClients) AS _Total
FROM dbo.MyTable mt
WHERE mt.[Month] = #dmin
UNION ALL
SELECT mt.[Month] AS _Month, ((mt.NewClients - mt.OnHoldClients) + ccc._Total) AS _Total
FROM dbo.MyTable mt
CROSS APPLY (SELECT cc._Total FROM (SELECT c._Total,
CAST((row_number() OVER (ORDER BY c._Month DESC)) AS int) as _Rank
FROM cte c WHERE c._Month < mt.[Month]) as cc
WHERE cc._Rank = 1) AS ccc
WHERE mt.[Month] > #dmin
)
SELECT c._Month, max(c._Total) AS Total
FROM cte c
GROUP BY c._Month
It is a recursive CTE structure that goes about each record all along the way to the initial month and adds up to the final Total value. This query only includes Month and Total fields but you can easily add the other 2 to the list of projection.
Try this
;WITH CTE([Month],NewClients,OnHoldClients)
AS
(
SELECT '5-2017',10,2 UNION ALL
SELECT '6-2017',16,4 UNION ALL
SELECT '7-2017',11,1 UNION ALL
SELECT '8-2017',15,6 UNION ALL
SELECT '9-2017',18,7
)
SELECT [Month],
NewClients,
OnHoldClients,
SUM(MonthTotal)OVER( ORDER BY [Month]) AS Total
FROM
(
SELECT [Month],
NewClients,
OnHoldClients,
SUM(NewClients-OnHoldClients)OVER(PArtition by [Month] Order by [Month]) AS MonthTotal
FROM CTE
)dt
Result,Demo:http://rextester.com/DKLG54359
Month NewClients OnHoldClients Total
--------------------------------------------
5-2017 10 2 8
6-2017 16 4 20
7-2017 11 1 30
8-2017 15 6 39
9-2017 18 7 50

How to use SQL query with havng count here?

I having Table(Tbl_Test) with following data.
RecordId BatchName Numbers MQC
1 20150443 321106 0
2 20150430 321107 0
3 20150430 321107 1
4 20150412 321110 2
5 20150430 321118
6 20150430 321120
7 20150432 321120
8 20150430 321126
9 20150432 321127
10 20150430 321129
11 20150431 321129
From the above table I want output like,Numbers columns whose count is greater than 1.
RecordId BatchName Numbers MQC
2 20150430 321107 0
3 20150430 321107 1
6 20150430 321120
7 20150432 321120
10 20150430 321129
11 20150431 321129
I've tried the following select but without success:
select RecordId,BatchName,Numbers,MQC
from Tbl_Test
group by RecordId,BatchName,Numbers,MQC
having count(Numbers)>1
;WITH CTE AS
(
SELECT
RecordId,
BatchName,
Numbers,
MQC,
count(*) over (partition by Numbers) cnt
FROM tbl_test
)
SELECT
RecordId, BatchName, Numbers, MQC
FROM CTE
WHERE cnt > 1
You can use GROUP BY with HAVING and IN.Something like this.
SELECT * FROM Tbl_Test
WHERE Numbers IN
(
SELECT Numbers
FROM Tbl_Test
GROUP BY Numbers
HAVING COUNT(*) > 1
)
One solution would be to use a Common table expression.
Try this:
;With CTE AS
(
SELECT Numbers,
Count(1) As NumberOfRows
FROM Tbl_Test
GROUP BY Numbers
)
SELECT T.*
FROM Tbl_Test T
INNER JOIN CTE ON(T.Numbers = CTE.Numbers)
WHERE NumberOfRows > 1
play with it your self on sql fiddle
Use count on RecordID with group By on MQC.
'Count(RecordId) Group By MQC' should work for you.

SQL Server Order by numeric varchar

I have this query:
select cast(MONTH(c.dataregistro) as VARCHAR(2)) as DATA, numberofquotesreturned, count(*) AS CountNumberQuotes from contratacao c
inner join teleportpedidocotacao tpc on c .idcontratacao = tpc.idcontratacao
where cast(c.dataregistro as date) > '2014-01-01 00:00:00' AND numberofquotesreturned = 5
group by numberofquotesreturned, cast(MONTH(c.dataregistro) as VARCHAR(2))
order by cast(MONTH(c.dataregistro) as VARCHAR(2))
The results are:
10 5 347
2 5 112
3 5 914
4 5 786
5 5 1184
6 5 2361
7 5 2430
8 5 2184
9 5 2709
I want to order by the whole number on the first column and as you can see the '10' comes first. How can I fix it?
Just remove the cast to varchar:
select MONTH(c.dataregistro) as DATA, numberofquotesreturned, count(*) AS CountNumberQuotes from contratacao c
inner join teleportpedidocotacao tpc on c .idcontratacao = tpc.idcontratacao
where cast(c.dataregistro as date) > '2014-01-01 00:00:00' AND numberofquotesreturned = 5
group by numberofquotesreturned, MONTH(c.dataregistro)
order by MONTH(c.dataregistro)

Resources