10

次の列を持つ株式データを含む MS SQL テーブルがありますId, Symbol, Date, Open, High, Low, Close

テーブルに自分で参加したいので、 の日々の変化率を取得できますClose

すべてのレコードに前のセッションのデータも含まれるように、テーブル自体を結合するクエリを作成する必要があります (昨日の日付は使用できないことに注意してください)。

私の考えは、次のようなことをすることです:

select * from quotes t1
inner join quotes t2
on t1.symbol = t2.symbol and
t2.date = (select max(date) from quotes where symbol = t1.symbol and date < t1.date)

ただし、それが正しい/最速の方法であるかどうかはわかりません。パフォーマンスについて考えるとき、何を考慮に入れる必要がありますか? (たとえば、(Symbol, Date) ペアに UNIQUE インデックスを配置すると、パフォーマンスが向上しますか?)

このテーブルには、毎年約 100,000 の新しいレコードが追加されます。MS SQL Server 2008 を使用しています

4

7 に答える 7

9

1 つのオプションは、再帰的な cte を使用することです (要件を正しく理解している場合)。

WITH RNCTE AS (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date) rn
        FROM quotes
  ),
CTE AS (
  SELECT symbol, date, rn, cast(0 as decimal(10,2)) perc, closed
  FROM RNCTE
  WHERE rn = 1
  UNION ALL
  SELECT r.symbol, r.date, r.rn, cast(c.closed/r.closed as decimal(10,2)) perc, r.closed
  FROM CTE c 
    JOIN RNCTE r on c.symbol = r.symbol AND c.rn+1 = r.rn
  )
SELECT * FROM CTE
ORDER BY symbol, date

SQL フィドルのデモ

パーセンテージの変化として使用する各シンボルの現在の合計が必要な場合は、その金額の追加の列を追加するのは簡単です-あなたの意図が完全にはわからなかったので、上記は現在のクローズ金額を前回の決算額。

于 2013-03-20T15:23:13.937 に答える
5

次のようなものが SQLite で機能します。

SELECT ..
FROM quotes t1, quotes t2
WHERE t1.symbol = t2.symbol
    AND t1.date < t2.date
GROUP BY t2.ID
    HAVING t2.date = MIN(t2.date)

SQLite が最も単純なものであることを考えると、おそらく MSSQL でもこれは最小限の変更で機能します。

于 2014-11-13T13:55:24.787 に答える
2

索引付け(symbol, date)

SELECT *
FROM quotes q_curr
CROSS APPLY (
  SELECT TOP(1) *
  FROM quotes
  WHERE symbol = q_curr.symbol
    AND date < q_curr.date
  ORDER BY date DESC
) q_prev
于 2015-06-26T15:59:56.630 に答える
1

CTEおよびROW_NUMBERランキング関数でオプションを使用できます

 ;WITH cte AS
 (
  SELECT symbol, date, [Open], [High], [Low], [Close],
         ROW_NUMBER() OVER(PARTITION BY symbol ORDER BY date) AS Id
  FROM quotes
  )
  SELECT c1.Id, c1.symbol, c1.date, c1.[Open], c1.[High], c1.[Low], c1.[Close], 
         ISNULL(c2.[Close] / c1.[Close], 0) AS perc
  FROM cte c1 LEFT JOIN cte c2 ON c1.symbol = c2.symbol AND c1.Id = c2.Id + 1
  ORDER BY c1.symbol, c1.date

パフォーマンスを向上させる (ソートと RID ルックアップを回避する) には、このインデックスを使用します

CREATE INDEX ix_symbol$date_quotes ON quotes(symbol, date) INCLUDE([Open], [High], [Low], [Close])

SQLFiddle の簡単なデモ

于 2013-03-20T15:29:17.070 に答える
1

次のようにします。

with OrderedQuotes as
(
    select 
        row_number() over(order by Symbol, Date) RowNum, 
        ID, 
        Symbol, 
        Date, 
        Open, 
        High, 
        Low, 
        Close
      from Quotes
)
select
    a.Symbol,
    a.Date,
    a.Open,
    a.High,
    a.Low,
    a.Close,
    a.Date PrevDate,
    a.Open PrevOpen,
    a.High PrevHigh,
    a.Low PrevLow,
    a.Close PrevClose,

    b.Close-a.Close/a.Close PctChange

  from OrderedQuotes a
  join OrderedQuotes b on a.Symbol = b.Symbol and a.RowNum = b.RowNum + 1

最後の結合を左結合に変更すると、各シンボルの最初の日付の行が得られますが、それが必要かどうかはわかりません。

于 2013-03-20T15:33:32.993 に答える
0

次のようなことができます。

DECLARE @Today DATETIME
SELECT @Today = DATEADD(DAY, 0, DATEDIFF(DAY, 0, CURRENT_TIMESTAMP))

;WITH today AS
(
    SELECT  Id ,
            Symbol ,
            Date ,
            [OPEN] ,
            High ,
            LOW ,
            [CLOSE],
            DATEADD(DAY, -1, Date) AS yesterday 
    FROM quotes
    WHERE date = @today
)
SELECT *
FROM today
LEFT JOIN quotes yesterday ON today.Symbol = yesterday.Symbol
    AND today.yesterday = yesterday.Date

そうすれば、オプションである場合、「今日」の結果を制限できます。

編集: 他の質問としてリストされている CTE はうまくいくかもしれませんが、100K 行以上を扱う場合は ROW_NUMBER の使用をためらう傾向があります。前日が常に昨日であるとは限らない場合は、独自のクエリで前日のチェックを引き出して、参照用に使用することを好む傾向があります。

DECLARE @Today DATETIME, @PreviousDay DATETIME
SELECT @Today = DATEADD(DAY, 0, DATEDIFF(DAY, 0, CURRENT_TIMESTAMP));
SELECT @PreviousDay = MAX(Date) FROM quotes  WHERE Date < @Today;
WITH today AS
(
    SELECT  Id ,
            Symbol ,
            Date ,
            [OPEN] ,
            High ,
            LOW ,
            [CLOSE]
    FROM quotes 
    WHERE date = @today
)
SELECT *
FROM today
LEFT JOIN quotes AS previousday
    ON today.Symbol = previousday.Symbol
    AND previousday.Date = @PreviousDay
于 2013-03-20T15:20:32.487 に答える
0

あなたが持っていたものは大丈夫です。サブクエリを結合に変換することが役立つかどうかはわかりません。ただし、あなたがそれを要求したので、それを行う方法は、テーブルをもう一度それ自体に結合することかもしれません.

select *
from quotes t1
inner join quotes t2
   on t1.symbol = t2.symbol and t1.date > t2.date
left outer join quotes t3
   on t2.symbol = t3.symbol and t2.date > t3.date
where t3.date is null
于 2013-03-20T15:25:26.373 に答える