2012-08-24 42 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他们真正的定义是。