好吧,讓我重申我對你的問題的理解:你想要一個存儲過程,可以獲取可變數量的參數並傳回匹配的頂行偏好的加權順序參數在SQL Server 2005上傳遞。
理想情況下,它將使用WHERE子句來防止全表掃描以及利用索引,並將「短路」搜索 - 您不想搜索所有可能的組合,如果可以早找到的話。也許我們也可以允許其他比較器比如=,例如> =用於日期,LIKE用於字符串等。
一種可能的方式是像在this article中那樣傳遞XML參數並使用.Net存儲過程,但讓我們保持原樣現在是香草T-SQL。
這看起來對我來說,在參數二進制搜索:搜索所有參數,然後刪除最後一個,然後掛斷第二個最後一個,但包括最後一個,等
讓我們傳遞的參數作爲由於存儲過程不允許將數組作爲參數傳遞,因此使用分隔字符串。這將允許我們在我們的存儲過程中獲取可變數量的參數,而不需要爲每個參數變化存儲過程。
爲了讓任何形式的比較,我們會通過整個WHERE子句列表,就像這樣:標題LIKE「%%的東西」
傳遞多個參數指在一個字符串界定他們。我們將使用代字符〜字符來分隔參數,如下所示:author ='Chris Latta'〜title like'%something%'〜pages> = 100
然後,這只是一個做二進制加權的問題搜索滿足我們的有序參數列表的第一行(希望存儲過程帶有註釋是不言自明的,但如果沒有,請告訴我)。請注意,總是保證結果(假定您的表至少有一行),因爲最後的搜索是無參數的。
這裏是存儲過程的代碼:
CREATE PROCEDURE FirstMatch
@SearchParams VARCHAR(2000)
AS
BEGIN
DECLARE @SQLstmt NVARCHAR(2000)
DECLARE @WhereClause NVARCHAR(2000)
DECLARE @OrderByClause NVARCHAR(500)
DECLARE @NumParams INT
DECLARE @Pos INT
DECLARE @BinarySearch INT
DECLARE @Rows INT
-- Create a temporary table to store our parameters
CREATE TABLE #params
(
BitMask int, -- Uniquely identifying bit mask
FieldName VARCHAR(100), -- The field name for use in the ORDER BY clause
WhereClause VARCHAR(100) -- The bit to use in the WHERE clause
)
-- Temporary table identical to our result set (the books table) so intermediate results arent output
CREATE TABLE #junk
(
id INT,
author VARCHAR(50),
title VARCHAR(50),
printed DATETIME,
pages INT
)
-- Ill use tilde ~ as the delimiter that separates parameters
SET @SearchParams = LTRIM(RTRIM(@SearchParams))+ '~'
SET @Pos = CHARINDEX('~', @SearchParams, 1)
SET @NumParams = 0
-- Populate the #params table with the delimited parameters passed
IF REPLACE(@SearchParams, '~', '') <> ''
BEGIN
WHILE @Pos > 0
BEGIN
SET @NumParams = @NumParams + 1
SET @WhereClause = LTRIM(RTRIM(LEFT(@SearchParams, @Pos - 1)))
IF @WhereClause <> ''
BEGIN
-- This assumes your field names dont have spaces and that you leave a space between the field name and the comparator
INSERT INTO #params (BitMask, FieldName, WhereClause) VALUES (POWER(2, @NumParams - 1), LTRIM(RTRIM(LEFT(@WhereClause, CHARINDEX(' ', @WhereClause, 1) - 1))), @WhereClause)
END
SET @SearchParams = RIGHT(@SearchParams, LEN(@SearchParams) - @Pos)
SET @Pos = CHARINDEX('~', @SearchParams, 1)
END
END
-- Set the binary search to search from all parameters down to one in order of preference
SET @BinarySearch = POWER(2, @NumParams)
SET @Rows = 0
WHILE (@BinarySearch > 0) AND (@Rows = 0)
BEGIN
SET @BinarySearch = @BinarySearch - 1
SET @WhereClause = ' WHERE '
SET @OrderByClause = ' ORDER BY '
SELECT @OrderByClause = @OrderByClause + FieldName + ', ' FROM #params WHERE (@BinarySearch & BitMask) = BitMask ORDER BY BitMask
SET @OrderByClause = LEFT(@OrderByClause, LEN(@OrderByClause) - 1) -- Remove the trailing comma
SELECT @WhereClause = @WhereClause + WhereClause + ' AND ' FROM #params WHERE (@BinarySearch & BitMask) = BitMask ORDER BY BitMask
SET @WhereClause = LEFT(@WhereClause, LEN(@WhereClause) - 4) -- Remove the trailing AND
IF @BinarySearch = 0
BEGIN
-- If nothing found so far, return the top row in the order of the parameters fields
SET @WhereClause = ''
-- Use the full order sequence of fields to return the results
SET @OrderByClause = ' ORDER BY '
SELECT @OrderByClause = @OrderByClause + FieldName + ', ' FROM #params ORDER BY BitMask
SET @OrderByClause = LEFT(@OrderByClause, LEN(@OrderByClause) - 1) -- Remove the trailing comma
END
-- Find out if there are any results for this search
SET @SQLstmt = 'SELECT TOP 1 id, author, title, printed, pages INTO #junk FROM books' + @WhereClause + @OrderByClause
Exec (@SQLstmt)
SET @Rows = @@RowCount
END
-- Stop the result set being eaten by the junk table
SET @SQLstmt = REPLACE(@SQLstmt, 'INTO #junk ', '')
-- Uncomment the next line to see the SQL you are producing
--PRINT @SQLstmt
-- This gives the result set
Exec (@SQLstmt)
END
此存儲過程稱爲像這樣:
FirstMatch 'author = ''Chris Latta''~pages > 100~title like ''%something%'''
有你有它 - 對頂級結果加權一個完全可擴展,優化搜索優先順序。這是一個有趣的問題,並展示了您可以使用本機T-SQL實現的功能。
跟這個有幾個小問題:
- 它依賴於調用者知道,他們必須在字段名稱後留出空間爲參數正常工作
- 你不能有場用空格名字在其中 - 可以解決的一些努力
- 它假定相關的排序順序總是上升
- 下一個程序員有來看待這個過程會覺得你瘋了:)
使用AND連接WHERE子句中的條件時發生了什麼? – 2008-12-22 23:03:25
@JL這是否有趣? – 2008-12-23 19:11:48