查询查找具有最匹配列的记录,其中非匹配列具有空格?

时间:2012-08-24 17:24:16

标签: sql sql-server-2008-r2

问题

我正在尝试在SQL Server中编写存储过程以找到最佳匹配记录。给定5个输入参数@ A,@ B,@ C,@ D和@E(所有varchar50)对应于我表中的5列A,B,C,D和E,我想找到记录最匹配的列。在所选记录中不匹配的每列应包含空格''。

例如,如果输入“Sony”,“PlayStation”,“Controller”,“Black”,“Damaged”,我的表格包含以下列:

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

它应该返回第二行,因为2个参数匹配,而3个参数不匹配,则有空格。我不想返回第一行,因为即使4个参数匹配,中间的一个不匹配,也不是空格。如果它是一个空间,那么第一行就是赢家。

我的方法

我无法透露各种具体细节,但我的基本方法(请注意我是SQL新手)是测试从MOST特定到LEAST特定的每个组合。所以我的查询看起来像这样:

-- 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种配置,因为某些排列将永远不会存在。即便如此,这似乎是实现我想要的非常低效的方式。最重要的是,它甚至没有工作。似乎比较空间是有问题的,因为正在进行一些自动修剪。在任何情况下,我目前的方法似乎效率低下并且不起作用 - 所以我求助于你。

3 个答案:

答案 0 :(得分: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', ' ', ' '

没有任何东西会被退回,因为它们都在第三栏中有“单位”。

答案 1 :(得分:1)

我会对5个比较中的每个进行评分(在A-E列之间),然后将得分加起来。

当任何一行的colA = colA时,它得分为1。

当colA<> colA和第二行的colA ='',得分为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值为null。然后,为了找到您的最高得分匹配,您可以按score降序排序。

答案 2 :(得分:0)

在SQl Server中,您可以使用CTE和Nullif之类的(未经测试的)

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

;有计数(id,ACount,BCount,CCount,DCount,ECount) 如 (选择id,sum(A = @a或nullif(a,'')为空的情况,然后是1,否则为0)作为ACount ,sum(b = @b或nullif(b,'')的情况为null,然后是1,0结束)为bCount ,sum(c = @c或nullif(c,'')的情况为null,然后是1,0结束)作为cCount ,sum(d = @d或nullif(d,'')的情况为null,然后是1,0结束)为dCount ,sum(e = @e或nullif(e,'')为空的情况,然后是1,否则为0结束)为eCount 来自dbo.items)

,总计(id,Totalcount) 如 (从计数中选择id,max(ACount + BCount + CCount + DCount + ECount)作为totalCount 其中Acount<> 0和BCount<> 0和CCount<> 0和DCount<> 0和ECount<> 0 按ID分组

选择i.id,i.a,i.b,i.c,i.d,即 来自dbo.items我 在i.id = t.id上加入总计t 当然,参数应该是他们真正的定义。