我认为自己对 T-SQL 相当精通,而且我通常能够很好地优化查询而不会失去可读性。简而言之:我喜欢我的 SQL 简短、描述性、声明性和优雅。
虽然以下代码有效,但我有两个问题:
- 我正在使用游标,我无法摆脱我脑后的感觉,即使用 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
由于它可能并不完全明显,因此我在这里尝试做的类似于以下准 SQL
SELECT DISTINCT TOP(@Limit) ID, Url, Referer
FROM Log
ORDER BY ID DESC
基本上是为了得到最后一个唯一的引用(不是唯一的行),它通常包含重复项,并且按降序排列。这绝对是棘手的地方。
数据是非常简单的 HTTP 日志。ID 字段只是一个唯一的行标识符,Url 是完整的 url requesten,Referer 是该请求的 HTTP referer。任何值都不能为空,但referer 可以为空(即'')。IsSiteLocal 只是一个简单的过滤功能,用于排除来自我自己网站的引用者。
如果有人想要一些样本数据,我可以上传一个小的数据库备份,这样你就有一些东西可以玩弄了。
样本数据可以在这里找到: http ://svada.kjonigsen.net/files/IISLogsDBBackup.zip