扩大条件下案例样式选择的最佳实践

Best practises for case style selects with widening conditions

我们正在设计一个解决方案,该解决方案将询问交易数据,以便 return 根据第一组规则进行匹配 return 结果,其中每个 select 比以前的。目标是获得 return 结果的最窄搜索范围。

这是一个例子。考虑一个包含车辆数据的场景,我们已获得以下三个值:

  1. 车辆的 VIN
  2. 车辆登记号
  3. 车辆所在城市

然后我们要查询交易数据以 return 匹配该值。一个重要的区别是它可以是一对多匹配,因为交易数据具有额外的关系,这意味着重复的车辆可能驻留在交易数据中。在一对多匹配中,我们需要匹配过程中所有匹配的 ID

我们要查询数据的顺序如下(示例):

来自交易数据:

如果none存在:

如果none存在:

这个例子只有三个加宽条件,然而,在我们的应用程序中,它实际上是 8 个左右。

这可以按顺序完成,如下图所示,但感觉不正确,可能有更好的基于集合的操作来完成它,但我想不出如何创建它。

以下是按顺序完成的方法:

-- assume these values are passed in
declare @vin varchar(50) = 'abcdefg'
declare @rego varchar(50) = '123456'
declare @city = 'Sydney'

-- create a table to hold the results
declare @ids table(id int)

-- try the narrowest search: matching VIN and City
insert into @ids(id)
select id from TransactionalData where Vin = @vin and City = @city

if ((select count(*) from @ids ) = 0)
begin
  -- try the next narrowest search: matching VIN
  insert into @ids(id)
  select id from TransactionalData where Vin = @vin

  if ((select count(*) from @ids ) = 0)
  begin
    -- try the next narrowest search: matching Rego and City
    insert into @ids(id)
    select id from trasnactionaldata where Rego = @rego and City = @city
  end
end

-- at this point, @ids will contain the ids from the narrowest search

它会起作用,但它似乎不是正确的方法。谁能建议如何在基于单个集合的操作中做到这一点?

非常感谢

也许是这样的。您在 WHERE 子句中指定所需条件,然后对结果进行匹配计数并将其排名

select *,
       match_cnt = case when td.vin  = @vin then 1 else 0 end
                 + case when td.rego = @rego then 1 else 0 end
                 + case when td.city = @city then 1 else 0 end
from   TransactionalData td
where  td.vin  = @vin
or     td.rego = @rego
or     td.city = @city
order by match_cnt desc

如果我没理解错的话,我们可以用一个列来表示优先级,这意味着您希望按 CASE WHEN 表达式

插入顺序
;WITH CTE AS (
   SELECT id, CASE WHEN Vin = @vin and City = @city THEN 3 
                    WHEN Vin = @vin THEN 2 
                    WHEN Rego = @rego and City = @cit THEN 1 
                END priority 
  FROM TransactionalData where (Vin = @vin and City = @city) OR (Vin = @vin) OR (Rego = @rego and City = @city)
)
INSERT INTO @ids(id)
SELECT id
FROM CTE c 
WHERE priority = (SELECT MAX(priority) FROM CTE)

一种方法是使用 EXISTS 而不是 COUNT

您也可以使用 CASE

WITH CTE AS (
    SELECT 
        id,
        CASE 
            WHEN Vin = @vin and City = @city then 1
            WHEN Vin = @vin then 2
            WHEN Rego = @rego and City = @city then 3
        END as lvl
    FROM TransactionalData
)
INSERT into @ids(id) 
SELECT 
    id 
FROM 
    CTE
WHERE
    lvl = (SELECT MIN(lvl) FROM CTE)

但是你的做法是正确的