T-SQL Query返回最接近的值

时间:2017-10-06 13:21:50

标签: sql sql-server tsql

我在SQL Server表中获得了一些数据如下:

DateTime                Bid       Ask 
02/10/2017 09:59.323    123.111   123.894 
02/10/2017 10:01.432    123.321   124.001  
02/10/2017 10:03.132    123.421   124.121
02/10/2017 10:03.983    123.121   123.721 
02/10/2017 10:04.342    123.587   124.200

我想询问的是每个第二时间段的买入价和卖出价。例如:

  • 10:00.000,出价为123.111,Ask为123.894
  • 10:01.000,出价为123.111,Ask为123.894
  • 10:02.000,出价为123.321,Ask为124.001
  • 10:03.000,出价为123.321,Ask为124.001
  • 10:04.000标价为123.121,询价为123.721

因此,SQL需要在每个第二个值之前返回Date Time的Bid和Ask值。

例如:

  • 10:00.000使用09:59.323
  • 10:01.000使用09:59.323
  • 10:02.000使用10:01.432
  • 10:03.000使用10:01.432
  • 10:04.000使用10:03.983

我的查询将在开始日期和结束日期/时间之间返回值,因此它将返回多行。

6 个答案:

答案 0 :(得分:0)

按日期时间降序对表格进行排序,将返回值限制为1,然后确保返回的任何值都低于提供的日期时间。

[编辑]

select top 1 bid, ask
from datatable
where itsdatetime <= '02/10/2017 10:00.000'
order by itsdatetime desc

您可以获得更多创意并将其置于条件子查询中。

select *
from requiretimes rt
join datatable dt on dt.itsdatetime = (select top 1 itsdatetime
                    from datatable
                    where itsdatetime <= rt.requireddatetime
                    order by itsdatetime desc)

答案 1 :(得分:0)

您可以尝试此查询:

if object_id('tempdb..#Table1') is not null
  drop table #Table1
go
create table #Table1(
DateTime datetime
,Bid float     
,Ask float)

insert into #Table1
select '02/10/2017 09:59.323', 123.111, 123.894 
union all select '02/10/2017 10:01.432', 123.321, 124.001  
union all select '02/10/2017 10:03.132', 123.421, 124.121
union all select '02/10/2017 10:03.983', 123.121, 123.721 
union all select '02/10/2017 10:04.342', 123.587, 124.200

declare @start_date datetime
      , @end_date datetime

select @start_date = dateadd(mi, datediff(mi, 0, min(DateTime)) + 1, 0)
  from #Table1

select @end_date = dateadd(mi, datediff(mi, 0, max(DateTime)), 0) 
  from #Table1

;with generates_dates as(
select @start_date as dt
union all
select dateadd(mi, 1, dt) as dt
  from generates_dates
  where dt < @end_date)

select t1.dt
     , t2.Bid
     , t2.Ask
  from generates_dates t1
    cross apply(select top 1 Bid, Ask 
                  from #Table1 t2 
                  where t2.DateTime < t1.dt 
                  order by t2.DateTime desc)t2(Bid, Ask)
  option (maxrecursion 0)

答案 2 :(得分:0)

这有两个部分:

  1. 创建一个投影,保存您的时间戳:10:00.000,10:01.000,10:02.000等。这里的答案很难显示,因为我们没有知道您使用什么标准来确定开始和结束范围,并且因为您的问题会询问秒数,但您的时间戳值实际上显示分钟。如果您需要这方面的帮助,Google和Stack Overflow上有很多结果可用于创建投影,数字表格或序列。

  2. 使用OUTER APPLY运算符将投影连接回原始数据。 OUTER APPLY可让您轻松准确显示投影中每件商品的正确记录。

  3. WITH times As (
        SELECT cast('2017-02-10 10:00.000' as datetime) "DateTime"
        UNION
        SELECT cast('2017-02-10 10:01.00' as datetime)
        UNION
        SELECT cast('2017-02-10 10:02.000' as datetime) 
        UNION
        SELECT cast('2017-02-10 10:03.000' as datetime)
        UNION
        SELECT cast('2017-02-10 10:04.000' as datetime)
        UNION
        SELECT cast('2017-02-10 10:05.000' as datetime)
    )
    SELECT t.[DateTime], u.[DateTime], u.Bid, u.Ask
    FROM times t
    CROSS APPLY ( 
          SELECT TOP 1 * 
          FROM [MyTable] 
          WHERE [DateTime] < t.[DateTime] 
          ORDER BY [DateTime] DESC
    ) u
    ORDER BY t.[DateTime]
    
      

    SQLFiddle

答案 3 :(得分:0)

DECLARE @T TABLE 
(
    d   DateTime, 
    bid MONEY,
    ask MONEY
)
INSERT INTO @T VALUES
('02/10/2017 09:59.323',    123.111,   123.894),
('02/10/2017 10:01.432',    123.321,   124.001),  
('02/10/2017 10:03.132',    123.421,   124.121),
('02/10/2017 10:03.983',    123.121,   123.721), 
('02/10/2017 10:04.342',    123.587,   124.200),
('03/10/2017 10:04.342',    123.587,   124.200)

;WITH sec AS 
(
    SELECT TOP (SELECT 60*60*24) ROW_NUMBER() OVER (ORDER BY 1/0) as s
    FROM master..spt_values a,master..spt_values m
), dd as
(
    SELECT DISTINCT CAST(d as date ) as d
    FROM @t
), Tbl as 
(
    SELECT
        DATEADD(ss,b.s,CAST(a.d as datetime)) as dat
    FROM     
        dd  a
    CROSS JOIN 
        sec b   
)
SELECT
    dat 
    ,c.*
FROM     tbl
CROSS APPLY 
(
    SELECT TOP 1 *
    FROM @t a
    WHERE 
        a.d >= tbl.dat
    ORDER BY 
        a.d ASC
) as c
WHERE 
    c.d >= dat  AND 
ORDER BY dat

答案 4 :(得分:0)

您将使用递归查询生成秒数。 (由于SQL Server不支持ANSI时间戳文字,因此您需要c:\Users\$USERNAME\npm\.npmrc。)然后通过CONVERT加入以每秒从表中获取最后一个条目。

CROSS APPLY

我根据你的描述在这里使用秒,而你的样本使用分钟代替。决定你真正需要的是什么。

答案 5 :(得分:0)

试试这个:

declare @idate datetime
declare @fdate datetime

select @idate = min(gendate) from BidAsk
select @fdate = max(gendate) from BidAsk

create table #temp (bid float, ask float, Gendate datetime)

while (@idate <= @fdate)
begin
   insert into #temp
   select top 1 Bid, Ask, @idate from BidAsk where @idate > GenDate
   order by GenDate desc

   set @idate = DATEADD(second,1,@idate)
end

select * from #temp