После того, как все зубы потянулись, вот что я придумал.Ваш ORDER BY Val
в предложении RANK() OVER()
не имеет смысла (поскольку Val - это всего лишь ранжирование, и его перераспределяют).Основываясь на вашем примере вывода, я предположил, что этот рейтинг должен определяться SymbolID.
USE tempdb;
GO
IF OBJECT_ID('dbo.SeriesFloat') IS NOT NULL
DROP TABLE dbo.SeriesFloat;
GO
-- suggest using DATE since you don't care about time
-- also does the Val column really need to be REAL?
-- could probably be an INT.
CREATE TABLE dbo.SeriesFloat
(
SeriesID SMALLINT,
SymbolID SMALLINT,
[Date] SMALLDATETIME,
Val REAL
);
INSERT dbo.SeriesFloat SELECT 12, 2011, '1999-01-08', 4215000;
INSERT dbo.SeriesFloat SELECT 12, 2012, '1999-01-08', 3215580;
INSERT dbo.SeriesFloat SELECT 12, 2013, '1999-01-08', 2029895;
INSERT dbo.SeriesFloat SELECT 12, 2011, '1999-01-09', 4029895;
INSERT dbo.SeriesFloat SELECT 12, 2012, '1999-01-09', 3395788;
INSERT dbo.SeriesFloat SELECT 12, 2013, '1999-01-09', 2029895;
INSERT dbo.SeriesFloat SELECT 35, 2012, '1999-01-09', 4;
INSERT dbo.SeriesFloat SELECT 35, 2013, '1999-01-09', 8;
-- change these two params to test larger ranges (up to 2,048 days):
DECLARE @Start DATE = '1999-01-08',
@End DATE = '1999-01-09',
@SeriesToRankID SMALLINT = 12,
@RankedSerieID SMALLINT = 35;
-- let's figure out the set of days - good for a range up to 2,048 days
-- if you need more than that, build a table of numbers
DECLARE @DaysInRange TABLE
(
d DATE
);
INSERT @DaysInRange
SELECT DISTINCT DATEADD(DAY, number, @Start)
FROM [master].dbo.spt_values
WHERE number BETWEEN 0 AND DATEDIFF(DAY, @Start, @End);
-- let's insert the rows that don't yet exist
INSERT dbo.SeriesFloat(SeriesID, SymbolID, [Date])
SELECT DISTINCT SeriesID = @RankedSerieID, s.SymbolID, d.d
FROM dbo.SeriesFloat AS s
CROSS JOIN @DaysInRange AS d
WHERE s.SeriesID = @SeriesToRankID
AND NOT EXISTS
(
SELECT 1 FROM dbo.SeriesFloat
WHERE SeriesID = @RankedSerieID
AND [Date] = d.d
AND SymbolID = s.SymbolID
);
-- then update all of them with ranking
WITH s AS
(
SELECT
SeriesID, SymbolID, [Date],
Val = ROW_NUMBER() OVER (PARTITION BY [Date] ORDER BY SymbolID)
FROM
dbo.SeriesFloat
WHERE
SeriesID = @RankedSerieID
)
UPDATE sf SET Val = s.Val
FROM dbo.SeriesFloat AS sf
INNER JOIN s
ON sf.SymbolID = s.SymbolID
AND sf.[Date] = s.[Date]
WHERE sf.SeriesID = @RankedSerieID;
SELECT SeriesID, SymbolID, [Date], Val
FROM dbo.SeriesFloat
ORDER BY SeriesID, [Date], Val;
GO
Мне не было интересно попробовать MERGE для решения этой проблемы, но вы можете проверить документы здесь:
http://msdn.microsoft.com/en-us/library/bb510625(SQL.100).aspx
Кроме того, зачем вам нужно сохранять рейтинг Val?Похоже, вы всегда сможете сгенерировать это во время запроса (используя представление, если вы часто используете этот столбец).