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