2017-06-19 7 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%以上異なる価格を持ちます。 結果には、2つの取引間の価格差のパーセンテージも表示されます。

SQLを以前に行っていない人にとっては、それを読んでいると私は本当に混乱しています。彼らはまた私に結果を提供しましたが、私は彼らがこの結果にどのように来たのか不明です。

期待される結果:

First_Trade Second_Trade PRICE_DIFF 
TRADE1  TRADE2   25 

このヘルプ場合、私はfiddleを作成しました。誰かが私に予想される結果を得る方法を示すことができれば、それは本の運動を理解する助けになるでしょう。

ありがとうございました

+0

あなたが実際に尋ねようとしているもの –

+0

可能であれば、その結果を得るために私を見せてくれる人。私は彼らがどのようにその結果を得たか分かりません。ありがとう – dave

+0

申し訳ありません! @dave私はあなたを正しく得ていない。 –

答えて

1

これで、結果が得られます。

1)列は全てのVARCHARである:

;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 

しかし、スキーマおよび一般的なクエリーパラメータを使用して多くの問題があります。これは、必要な結果を得るためには、すべて適切なデータ型にキャストする必要があるため、非常に非効率的です。 (私は@ Jeroen-Mostertの提案に従ってクエリをクリーンアップするためにCTEを使用しました)

2)テーブルが大きくなると、このクエリは使用される述語として非常にうまく機能しなくなります10秒のタイムスタンプ)は正しく索引付けされません。

+0

CTEを使用して、適切なクエリ内のすべてのキャストを取り除くことを検討してください。 (「はい」という事実にもかかわらず、元のテーブルの構造は多くのことを望みます。) –

1

他の答えとやや異なるアプローチですが、ほぼ同じ効果です。私は日付の範囲ではなく、日付の範囲を見つけるために 'Between'を使用します。

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 

これは、セキュリティ上の理由でパーティションが実行されていることに基づいています。コメントしたり、訂正を提案してください。