Я считаю себя достаточно опытным с T-SQL, и я обычно могу оптимизировать запрос довольно хорошо, не теряя удобочитаемости. Короче: мне нравится мой SQL короткий, описательный, декларативный и элегантный.Как преобразовать следующий код в SQL Server/T-SQL CTE?
Хотя следующий код работает, у меня есть две проблемы, связанные с ним:
- Я использую курсоры и я не могу отделаться от ощущения, я имею в задней части моей головы, что это могло быть сделано больше, эффективно используя CTE. Кроме того, курсоры не работают в представлениях, поэтому я не могу манипулировать результатами/диапазонами на стороне клиента или в зависимом SQL.
- Код реализован в хранимой процедуре, что приводит к той же проблеме, что и выше. Особенно с LInQ to SQL и автоматической подкачкой.
Так что, учитывая следующий SP, кто-нибудь видит какой-либо очевидный способ преобразования этого в простой выбор с использованием рекурсивных CTE? Я пробовал, провалился и подумал, что увижу, с чем может столкнуться сообщество переполнения стека.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[usp_GetLastReferers]
(
@Limit int = NULL
)
AS
BEGIN
SET NOCOUNT ON
CREATE TABLE #Referer
(
ID int,
Url nvarchar(500),
Referer nvarchar(500)
)
DECLARE @ID int
DECLARE @Url nvarchar(500)
DECLARE @Referer nvarchar(500)
DECLARE @Count int
SET @Count = 0
DECLARE LogCursor CURSOR FORWARD_ONLY READ_ONLY FOR
SELECT ID, Url, Referer FROM Log WHERE Referer <> '' ORDER BY ID DESC
OPEN LogCursor
FETCH NEXT FROM LogCursor INTO @ID, @Url, @Referer
WHILE @@FETCH_STATUS = 0 AND (@Count < @Limit OR @Limit IS NULL)
BEGIN
DECLARE @Hits int
SELECT @Hits = COUNT(*)
FROM #Referer
WHERE Referer = @Referer
DECLARE @IsLocal bit
SELECT @IsLocal = dbo.IsLocalSite(@Referer)
IF (@Hits = 0 OR @Hits IS NULL) AND @IsLocal = 0
BEGIN
INSERT INTO #Referer(ID,Url,Referer) VALUES (@ID,@Url,@Referer)
SET @Count = @Count + 1
END
FETCH NEXT FROM LogCursor INTO @ID, @Url, @Referer
END
CLOSE LogCursor
DEALLOCATE LogCursor
SELECT *
FROM #Referer
DROP TABLE #Referer
SET NOCOUNT OFF
END
Поскольку она не может быть совершенно очевидно, что я пытаюсь сделать здесь сродни TOTHE следующие квази SQL
SELECT DISTINCT TOP(@Limit) ID, Url, Referer
FROM Log
ORDER BY ID DESC
В основном, чтобы получить последний уникальный относится (не уникальные строки) , которые часто содержат дубликаты и в порядке убывания. Это определенно, где это становится сложно.
Данные довольно простые протоколы HTTP. Поле идентификатора - это просто уникальный идентификатор строки, Url - полный запрос URL, а Referer - HTTP-референт для этого запроса. Ни одно из значений не может быть нулевым, но референт может быть пустым (т.е. ''). IsSiteLocal - это просто простая функция фильтрации, чтобы исключить ссылки, исходящие из моих собственных сайтов.
Если кто-то хочет, чтобы некоторые образцы данных были заполнены, я могу загрузить небольшую резервную копию базы данных, чтобы у вас было что-то, с чем можно было обмануть.
Sample-данные можно найти здесь: http://svada.kjonigsen.net/files/IISLogsDBBackup.zip
Возможно, что-то в некоторых примерах данных? –
Хотя это значительно больше, чем мое, оно все еще не ведет себя абсолютно правильно или, как я хочу.Следующий код выборки использовать SQL запеченный в небольшой тест: DECLARE @Limit Int = 20 ; С Referers А.С. ( \t Выбор TOP (@Limit) l.Url, l.Referer, MAX (ID) AS ' ID» \t из журнала л \t где 0 = dbo.IsLocalSite (l.Referer) \t И l.Referer <> '' \t GROUP BY l.Url, l.Referer \t ORDER BY 3 убывание ) , JustReferers AS ( \t SELECT DISTINCT Referer \t ОТ Referer s ) SELECT COUNT (*) ОТ JustReferers -! = @Limit для достаточно большого количества @Limit. Вызывает неправильный пейджинг. –
вы можете добавить некоторые примеры данных, которые нам не нужно загружать? – DForck42