0

问题

我正在尝试在 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 新手)是测试从最特定到最不特定的每个组合。所以我的查询看起来像这样:

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

4

3 回答 3

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', ' ', ' '

不会返回任何内容,因为两者在第三列中都有“单位”。

于 2012-08-24T17:46:28.327 回答
1

我会对 5 个比较中的每一个(AE 列之间)进行评分,然后将分数相加。

当 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

我假设您将在再次评分之前将所有非空分数设置为空。

要合计一行的分数,只需

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

任何空值都会导致该score值为空。然后要查找得分最高的比赛,您可以按score降序排序。

于 2012-08-24T17:31:46.750 回答
0

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

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

;with counts (id, ACount, BCount,CCount,DCount,ECount) AS (select id, sum(case when A= @a or nullif(a, '') is null then 1 else 0 end) as ACount , sum(当 b= @b 或 nullif(b, '') 为 null 然后 1 else 0 end) 为 bCount 时的情况,sum(当 c= @c 或 nullif(c, '') 为 null 然后 1 else 0 end) 为cCount , sum(case when d= @d or nullif(d, '') is null then 1 else 0 end) as dCount , sum(case when e= @e or nullif(e, '') is null then 1 else 0 end) 作为来自 dbo.items 的 eCount)

, totals (id,Totalcount) AS (select id, max(ACount+BCount+CCount+DCount+ECount) as totalCount from counts where Acount<>0 and BCount<>0 and CCount<>0 and DCount<> 0 and ECount <>0 按 id 分组)

select i.id, ia, ib, ic, id, ie from dbo.items i join totals t on i.id = t.id 当然参数可以是它们的真实定义。

于 2012-08-24T17:52:41.217 回答