如何执行 Where 并通过相似的值查找
Posted
技术标签:
【中文标题】如何执行 Where 并通过相似的值查找【英文标题】:How to do a Where and find by similar values 【发布时间】:2020-09-03 10:16:25 【问题描述】:我正在停车场工作,路障中装有摄像头,当这些摄像头看到一个车牌时,该牌照将作为一个动作在数据库中注册。
如果此许可证有加入停车场的许可,停车场将开放,但摄像头并不完美获得许可证,也许有时我会获得一些不同字符的许可证。
我的意思是,例如,如果许可证是 7631 BHC,我可能会得到一个错误的值,它可能是 1931 5HD。
我想知道的是 SQL 中是否有任何方法可以在选择中执行 WHERE 以查看许可证是否具有权限,以获取可能是相机返回的许可证。
例如,在我展示的情况下,有 3 个字符与可能的值 (3,1,H) 匹配。
因此,我在后台使用 C# 工作时,如果有这 3 个字符的巧合,我会说如果有超过 2 个巧合,障碍就会打开。
您知道任何返回可能许可证的选择方法吗?
我尝试了函数 Difference() 但此选项对我不起作用,因为总是返回 4(这意味着值非常相似)并且不是这种情况,因为具有值的许可证(9999 HHH,1234 ZZZ), by fare 不相似,除了字符串的结构。
【问题讨论】:
您想在 SQL 或 C# 中执行此操作? @Jamiec 在 SQL 中更好,但如果有办法在 C# 中进行此比较不是问题。 您可能想查看 Levenshtein 距离。但是,您的问题的真正答案是 SQL 没有内置的模糊匹配机制来满足您的特定要求。 【参考方案1】:给定一个用户定义的函数:
CREATE FUNCTION dbo.CountMatches(@value NVARCHAR(100), @match NVARCHAR(100))
RETURNS INT AS
BEGIN
DECLARE @i INT = 1;
DECLARE @count INT = 0
WHILE(@i < LEN(@match) AND @i<LEN(@value))
BEGIN
IF(SUBSTRING(@value,@i,1) = SUBSTRING(@match,@i,1))
BEGIN
SET @count = @count+1
END
SET @i = @i+1
END
RETURN @count
END
您可以将其直接插入 where 子句:
declare @camera nvarchar(100) = '19315HD'
SELECT plate
FROM Plates
WHERE dbo.CountMatches(plate,@camera) >= 3
或者,你希望结果和 where 子句中的匹配计数使用 CTE 来保存调用该方法两次
declare @camera nvarchar(100) = '19315HD'
;with data
as
(
SELECT plate, dbo.CountMatches(plate, @camera) AS matchCount
FROM Plates
)
select plate,matchCount
from data
where matchCount>=3
现场示例:https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=e55ae3788616ce14c3888db19d4aa865
【讨论】:
【参考方案2】:如果您的输入数据和源数据将始终匹配模式 XXXX XXX
(8 个字符,第 5 个是空格),那么您可以对此进行硬编码...
样本数据
declare @input nvarchar(8) = '1931 5HD';
declare @plates table
(
plate nvarchar(8)
)
insert into @plates (plate) values
('1235 ZZZ'), -- 0 matches
('7631 BHC'), -- 3 matches
('1931 5HC'); -- 6 matches
解决方案
-- version 1
select p.plate
from @plates p
where case when substring(p.plate, 1, 1) = substring(@input, 1, 1) then 1 else 0 end
+ case when substring(p.plate, 2, 1) = substring(@input, 2, 1) then 1 else 0 end
+ case when substring(p.plate, 3, 1) = substring(@input, 3, 1) then 1 else 0 end
+ case when substring(p.plate, 4, 1) = substring(@input, 4, 1) then 1 else 0 end
+ case when substring(p.plate, 6, 1) = substring(@input, 6, 1) then 1 else 0 end
+ case when substring(p.plate, 7, 1) = substring(@input, 7, 1) then 1 else 0 end
+ case when substring(p.plate, 8, 1) = substring(@input, 8, 1) then 1 else 0 end > 2;
如果您想要匹配字符的计数,则可以在字段列表中复制 where 子句计算。这样,您甚至可以在按匹配字符数降序排序时仅选择 top 1
结果,从而为您提供最准确的车牌匹配。
-- version 2
select top 1
p.plate,
case when substring(p.plate, 1, 1) = substring(@input, 1, 1) then 1 else 0 end
+ case when substring(p.plate, 2, 1) = substring(@input, 2, 1) then 1 else 0 end
+ case when substring(p.plate, 3, 1) = substring(@input, 3, 1) then 1 else 0 end
+ case when substring(p.plate, 4, 1) = substring(@input, 4, 1) then 1 else 0 end
+ case when substring(p.plate, 6, 1) = substring(@input, 6, 1) then 1 else 0 end
+ case when substring(p.plate, 7, 1) = substring(@input, 7, 1) then 1 else 0 end
+ case when substring(p.plate, 8, 1) = substring(@input, 8, 1) then 1 else 0 end as MatchCount
from @plates p
where case when substring(p.plate, 1, 1) = substring(@input, 1, 1) then 1 else 0 end
+ case when substring(p.plate, 2, 1) = substring(@input, 2, 1) then 1 else 0 end
+ case when substring(p.plate, 3, 1) = substring(@input, 3, 1) then 1 else 0 end
+ case when substring(p.plate, 4, 1) = substring(@input, 4, 1) then 1 else 0 end
+ case when substring(p.plate, 6, 1) = substring(@input, 6, 1) then 1 else 0 end
+ case when substring(p.plate, 7, 1) = substring(@input, 7, 1) then 1 else 0 end
+ case when substring(p.plate, 8, 1) = substring(@input, 8, 1) then 1 else 0 end > 2
order by MatchCount desc;
另一个版本使用公用表表达式 (cte
) 来避免一些重复代码。灵感来自Jamiec's comment。
-- version 3
with cte as
(
select p.plate,
case when substring(p.plate, 1, 1) = substring(@input, 1, 1) then 1 else 0 end
+ case when substring(p.plate, 2, 1) = substring(@input, 2, 1) then 1 else 0 end
+ case when substring(p.plate, 3, 1) = substring(@input, 3, 1) then 1 else 0 end
+ case when substring(p.plate, 4, 1) = substring(@input, 4, 1) then 1 else 0 end
+ case when substring(p.plate, 6, 1) = substring(@input, 6, 1) then 1 else 0 end
+ case when substring(p.plate, 7, 1) = substring(@input, 7, 1) then 1 else 0 end
+ case when substring(p.plate, 8, 1) = substring(@input, 8, 1) then 1 else 0 end as MatchCount
from @plates p
)
select top 1 plate, MatchCount
from cte
where MatchCount > 2
order by MatchCount desc;
结果
-- version 1
plate
--------
7631 BHC
1931 5HC
-- version 2 & 3
plate MatchCount
-------- -----------
1931 5HC 6
【讨论】:
您可以使用 CTE,这样您就不必重复那个大而长的表达式两次。以上是关于如何执行 Where 并通过相似的值查找的主要内容,如果未能解决你的问题,请参考以下文章
如何从海量数据中找到相似数据--那些用于查找相似数据的哈希算法