如何以每个记录与"之前"记录连接的方式自行连接表?

Mic*_* B. 9 sql sql-server performance sql-server-2008

我有一个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)
Run Code Online (Sandbox Code Playgroud)

但是我不知道这是否是正确/最快的方式.在考虑性能时应该考虑什么?(例如,将UNIQUE索引放在(符号,日期)对上可以提高性能吗?)

此表中每年将有大约100,000条新记录.我正在使用MS SQL Server 2008

sge*_*des 9

一种选择是使用递归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
Run Code Online (Sandbox Code Playgroud)

SQL小提琴演示

如果您需要将每个符号的运行总计用作百分比更改,那么很容易为该数量添加额外的列 - 不能完全确定您的意图是什么,所以上面只是将当前关闭的金额除以以前的结算金额.


est*_*why 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)
Run Code Online (Sandbox Code Playgroud)

鉴于 SQLite 是最简单的一种,也许在 MSSQL 中,这也适用于最少的更改。


Jas*_*ish 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
Run Code Online (Sandbox Code Playgroud)

这样你就可以限制“今天”的结果(如果可以的话)。

编辑:作为其他问题列出的 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
Run Code Online (Sandbox Code Playgroud)