2017-06-19 59 views
4

我從來沒有做過SQL,我一直在閱讀它。我正在閱讀的書中有一個練習讓我開始,我也在查找一個名爲W3School的網站,這本書告訴我嘗試下面的內容;SQL表和數據提取

交易其具有以下結構 -

  • trade_id:主鍵
  • 時間戳:貿易的時間戳
  • 安全:底層安全(購買或在貿易銷售)
  • 量:標的數量(正面表示買入,負面表示已售出)
  • 價格:該交易的1個安全項目的價格

考慮下表

CREATE TABLE tbProduct 
     ([TRADE_ID] varchar(8), [TIMESTAMP] varchar(8), [SECURITY] varchar(8), [QUANTITY] varchar(8), [PRICE] varchar(8)) 
    ; 

    INSERT INTO tbProduct 
     ([TRADE_ID], [TIMESTAMP], [SECURITY], [QUANTITY], [PRICE]) 
    VALUES 
     ('TRADE1', '10:01:05', 'BP', '+100', '20'), 
     ('TRADE2', '10:01:06', 'BP', '+20', '15'), 
     ('TRADE3', '10:10:00', 'BP', '-100', '19'), 
     ('TRADE4', '10:10:01', 'BP', '-100', '19') 
    ; 

在這本書是告訴我編寫一個查詢發現,在10秒的範圍內發生的所有交易,並具有價格上漲10%以上不同。 結果還應列出兩筆交易之間差價的百分比。

對於一個以前沒有做過SQL的人來說,閱讀這件事實在讓我很困惑。他們也爲我提供了結果,但我不確定他們是如何得出這個結果的。

預期的結果:

First_Trade Second_Trade PRICE_DIFF 
TRADE1  TRADE2   25 

我創建了一個fiddle如果這幫助。如果有人能告訴我如何得到預期的結果,它會幫助我理解書本練習。

謝謝

+0

你實際上想要問什麼 –

+0

有人告訴我如果可能的話得到這個結果。我不確定他們是如何得到這個結果的。謝謝 – dave

+0

對不起! @dave我沒有正確理解你。 –

回答

1

這會得到你想要的結果。

;with cast_cte 
as 
(
    select [TRADE_ID], cast([TIMESTAMP] as datetime) timestamp, [SECURITY], [QUANTITY], cast([PRICE] as float) as price 
    from tbProduct 
) 
select t1.trade_id, t2.trade_id, datediff(ms, t1.timestamp, t2.timestamp) as milliseconds_diff, 
((t1.price - t2.price)/t1.price) * 100 as price_diff 
from cast_cte t1 
inner join cast_cte t2 
on datediff(ms, t1.timestamp, t2.timestamp) between 0 and 10000 
and t1.trade_id <> t2.trade_id 
where ((t1.price - t2.price)/t1.price) * 100 > 10 
or ((t1.price - t2.price)/t1.price) * 100 < -10 

然而,存在許多與該模式和通用查詢參數的問題:

1)的列是所有VARCHAR處理。這是非常低效的,因爲它們都需要轉換爲適當的數據類型才能得到您想要的結果。 (根據@ Jeroen-Mostert的建議,我使用CTE來清理查詢)

2)隨着表變大,這個查詢將開始執行非常糟糕的謂詞使用( 10秒時間戳)沒有正確索引。

+0

考慮使用CTE擺脫查詢中的所有這些強制轉換。 (儘管事實如此,原始表的結構仍有許多不足之處。) –

1

與其他答案略有不同,但效果幾乎相同。我使用「之間」來查找日期範圍而不是日期。

select 
    trade1.trade_ID as TRADE1, 
    trade2.trade_ID as TRADE2, 
    (cast(trade1.price as float)-cast(trade2.price as float))/cast(trade1.price as float)*100 as PRICE_DIFF_PERC 
from 
    tbProduct trade1 
inner join 
    tbProduct trade2 

on 
    trade2.timestamp between trade1.timestamp and dateadd(s,10,trade1.TIMESTAMP) 
and trade1.TRADE_ID <> trade2.TRADE_ID 

where (cast(trade1.price as float)-cast(trade2.price as float))/cast(trade1.price as float) >0.1 

該架構絕對可以改進;消除了對「CAST的需求將使這個更加清晰:

CREATE TABLE tbProduct2 
     ([TRADE_ID] varchar(8), [TIMESTAMP] datetime, [SECURITY] varchar(8), [QUANTITY] int, [PRICE] float) 
    ; 

允許你這樣做:

select *, 
    trade1.trade_ID as TRADE1, 
    trade2.trade_ID as TRADE2, 
    ((trade1.price-trade2.price)/trade1.price)*100 as PRICE_DIFF_PERC 
from 
    tbProduct2 trade1 
inner join 
    tbProduct2 trade2 

on 
    trade2.timestamp between trade1.timestamp and dateadd(s,10,trade1.TIMESTAMP) 
and trade1.TRADE_ID <> trade2.TRADE_ID 

where (trade1.price-trade2.price) /trade1.price >0.1 
    ; 
1

已經使用鉛的功能,以獲得預期的結果。試試這個:

select 
iq.trade_id as FIRST_TRADE, 
t1 as SECOND_TRADE, 
((price-t3)/price*100) as PRICE_DIFF 
from 
(
Select trade_id, timestamp, security, quantity, cast(price as float) price, 
     lead(trade_id) over (partition by security order by timestamp) t1 
     ,lead(timestamp) over (partition by security order by timestamp) t2 
     ,lead(cast(price as float)) over (partition by security order by timestamp) t3 
from tbProduct 
) iq 
where DATEDIFF(SECOND, iq.timestamp,iq.t2) between 0 and 10 
and ((price-t3)/price*100) > 10 

這是基於事實上,分區是通過安全完成的。隨意評論或建議更正。