2012-08-24 80 views
0

問題查詢查找具有最匹配列的記錄,其中不匹配的列有空格嗎?

我想在SQL Server中編寫存儲過程來查找最佳匹配記錄。給定5個輸入參數@A,@B,@C,@D和@E(所有varchar50),對應於我的表中的5列A,B,C,D和E,我想找到記錄最匹配的列。在所選記錄中不匹配的每列應包含一個空格「'。

舉例來說,如果我有輸入「索尼」,「的PlayStation」,「控制器」,「黑」,「損壞」,我的表包含以下幾列:

"Sony" "Playstation" "Unit" "Black" "Damaged" 
"Sony" "Playstation" " "  " "  " " 

它應該返回第二行,因爲2個參數匹配,3個不匹配,有空格。我不想返回第一行,因爲即使4個參數匹配,中間的不匹配,也不是空格。如果它是一個空間,第一排就是贏家。

我的做法

有一些我不能透露各種細節,但我的基本方法(請注意,我是一個新手SQL)是測試大多數具體到最不具體的每一個組合。所以我的查詢會是這個樣子:

-- start with most specific 
SELECT * FROM dbo.Items WHERE 
    A = @A 
    B = @B 
    C = @C 
    D = @D 
    E = @E 

-- if no matches, try next 
IF @@ROWCOUNT = 0 
SELECT * FROM dbo.Items WHERE 
    A = @A 
    B = @B 
    C = SPACE(1) 
    D = @D 
    E = @E 

... etc. 

對我來說,我只需要真正測試16點的配置,因爲有些排列永遠不會存在。即便如此,這似乎是實現我想要的非常低效的方式。最重要的是,它甚至沒有工作。看起來像空間比較是有問題的,因爲一些自動修剪正在進行。無論如何,我目前的做法似乎效率低下,並且不起作用 - 所以我轉向你尋求幫助。

+0

所以基本上排序最少數量的不正確匹配? – LittleBobbyTables

+0

@LittleBobbyTables,我想返回一個記錄,或者根本沒有。如果記錄被返回,它應該完全匹配除了「」之外的所有內容。 – Dalal

+0

btw,達拉爾,我想你可能有多個比賽,例如,colB中有一個匹配,colC中有一個空格,colB中有空格,colC中有空格。 – Beth

回答

2

是這樣的嗎?

-- Temp table to play with 
SELECT 1 AS Id, 'Sony' AS A, 'Playstation' AS B, 'Unit' AS C, 'Black' AS D, 
    'Damaged' AS E 
INTO #Items 
UNION SELECT 2, 'Sony', 'Playstation', ' ', ' ', ' ' 

-- The query 
DECLARE @a nvarchar(50), @b nvarchar(50), @c nvarchar(50), @d nvarchar(50), @e 

nvarchar(50) 
SET @a = 'Sony' 
SET @b = 'Playstation' 
SET @c = 'Controller' 
SET @d = 'Black' 
SET @e = 'Damaged' 

SELECT TOP 1 I.* 
FROM (
    SELECT ID, 
     CASE WHEN @a = a THEN 1 WHEN a = ' ' THEN 0 ELSE NULL END AS AResult, 
     CASE WHEN @b = b THEN 1 WHEN b = ' ' THEN 0 ELSE NULL END AS BResult, 
     CASE WHEN @c = c THEN 1 WHEN c = ' ' THEN 0 ELSE NULL END AS CResult, 
     CASE WHEN @d = d THEN 1 WHEN d = ' ' THEN 0 ELSE NULL END AS DResult, 
     CASE WHEN @e = e THEN 1 WHEN e = ' ' THEN 0 ELSE NULL END AS EResult 
    FROM #Items 
) IW 
INNER JOIN #Items I ON I.ID = IW.ID 
WHERE AResult IS NOT NULL AND BResult IS NOT NULL AND CResult IS NOT NULL 
    AND DResult IS NOT NULL AND EResult IS NOT NULL 
ORDER BY AResult + BResult + CResult + DResult + EResult DESC 

應該返回這個值:如果更改了臨時表,我用這個打

"Sony" "Playstation" " "  " "  " " 

SELECT 1 AS Id, 'Sony' AS A, 'Playstation' AS B, ' ' AS C, 'Black' AS D, 
    'Damaged' AS E 
INTO #Items 
UNION SELECT 2, 'Sony', 'Playstation', ' ', ' ', ' ' 

那麼你應該得到

"Sony" "Playstation" " " "Black" "Damaged" 

最後,如果你有這個您的臨時表示例:

SELECT 1 AS Id, 'Sony' AS A, 'Playstation' AS B, 'Unit' AS C, 'Black' AS D, 
    'Damaged' AS E 
INTO #Items 
UNION SELECT 2, 'Sony', 'Playstation', 'Unit', ' ', ' ' 

由於兩者在第三列都有'單元',因此不會返回任何結果。

+0

如果數據不存在,他如何獲取「單位」?(在第二個數據示例中)? –

+0

爲什麼你需要每個病例陳述的'else null'部分? – Beth

+0

@ X-Zero - 我的錯字 – LittleBobbyTables

1

我會對5個比較中的每一個(列A-E之間)進行評分,然後將得分相加。

當可樂=可樂上的任何行,它分數1.

當可樂<>可樂和第二行的可樂=「」,得分0

離開未刻痕的剩餘行(空colA分數的值)

最佳匹配的分數將是最高分,任何列中都沒有空分。

有意義嗎?

這裏是一個示例更新語句設置列的分數:

update table 
set scoreAcol = scoreA, scoreAcol = scoreB, scoreCcol = scoreC, scoreDcol = scoreD, scoreEcol = scoreE 
from 
    (select 
    case when cola = @a then 1 when cola= ' ' then 0 end as scoreA, 
    case when colb = @b then 1 when colb= ' ' then 0 end as scoreb, 
    case when colc = @c then 1 when colc= ' ' then 0 end as scorec, 
    case when cold = @d then 1 when cold= ' ' then 0 end as scored, 
    case when cole = @e then 1 when cole= ' ' then 0 end as scoree) s 
from table 

我假設你會再次進球之前設置所有非空的分數爲null。

爲了總一行的分數,只是

update table set score = scoreAcol + scoreBcol + scoreCcol + scoreDcol + scoreEcol 

任何空值將導致score值爲空。然後找到您的最高得分比賽,您可以按score降序排序。

+0

有點,但SQL只是不這樣工作。雖然我同意對列進行評分,但SQL本質上是以設置爲基礎的,並且按照您所建議的方式處理行並非最佳 - 您似乎像是一位勢在必行的程序員。這甚至不一定與OP的數據相匹配,因爲SQL中的行本來就是**無序的**,並且至少你必須對所有行進行評分(即使得到0分)。 –

+0

我並不是說用光標遍歷每一行,而是說引入5個新的'score'列並使用5個update語句來設置分數。 – Beth

+0

......除了假設OP將只搜索1件事,我非常懷疑是這樣。如果您建議運行更新,以便可以搜索多個內容,則可以立即消除其他用戶同時搜索數據庫的可能性。你可以用臨時表做些事情,但是一個好的'SELECT'的表現應該足以實現這一點。 –

0

在SQL Server中,你可以使用熱膨脹係數和NULLIF像這樣(未經)

declare @a int = 1 
, @B int = 2 
, @c int= 3 
, @d int= 4 
, @E int- 5 

;具有計數(ID,ACount,BCount,CCount,DCOUNT,ECount) AS (選擇ID,總和(當A = @a或nullif(a,'')爲空時,則1 else爲結束時)作爲ACount ,sum(當b = b或nullif(b,'')爲null時的情況,1 else 0 end )作爲bCount ,求和(當c = @c或nullif(c,'')爲空然後1 else爲結束時),sum(當d = @d或nullif(d,'') null then 1 else 0 end)as dCount ,sum(case when e = @e or nullif(即, '')是空值,則1點否則爲0結束)作爲eCount 從dbo.items)

,總計(ID,TOTALCOUNT) AS (選擇ID,MAX(ACount + BCount + CCount + DCOUNT + ECount )作爲從TOTALCOUNT計數 其中Acount <> 0且BCount <> 0且CCount <> 0和DCOUNT <> 0且ECount <> 0 組由ID)

選擇i.id,IA,IB,IC ,編號,即 from dbo.items i join totals t on i.id = t.id 當然參數wha是wha他們真正的定義是。