扩大条件下案例样式选择的最佳实践
Best practises for case style selects with widening conditions
我们正在设计一个解决方案,该解决方案将询问交易数据,以便 return 根据第一组规则进行匹配 return 结果,其中每个 select 比以前的。目标是获得 return 结果的最窄搜索范围。
这是一个例子。考虑一个包含车辆数据的场景,我们已获得以下三个值:
- 车辆的 VIN
- 车辆登记号
- 车辆所在城市
然后我们要查询交易数据以 return 匹配该值。一个重要的区别是它可以是一对多匹配,因为交易数据具有额外的关系,这意味着重复的车辆可能驻留在交易数据中。在一对多匹配中,我们需要匹配过程中所有匹配的 ID
我们要查询数据的顺序如下(示例):
来自交易数据:
- Return 具有匹配 VIN 和城市的所有车辆
如果none存在:
- Return 具有匹配 VIN 的所有车辆
如果none存在:
- Return 具有匹配 Rego 和 City 的所有车辆
这个例子只有三个加宽条件,然而,在我们的应用程序中,它实际上是 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)
但是你的做法是正确的
我们正在设计一个解决方案,该解决方案将询问交易数据,以便 return 根据第一组规则进行匹配 return 结果,其中每个 select 比以前的。目标是获得 return 结果的最窄搜索范围。
这是一个例子。考虑一个包含车辆数据的场景,我们已获得以下三个值:
- 车辆的 VIN
- 车辆登记号
- 车辆所在城市
然后我们要查询交易数据以 return 匹配该值。一个重要的区别是它可以是一对多匹配,因为交易数据具有额外的关系,这意味着重复的车辆可能驻留在交易数据中。在一对多匹配中,我们需要匹配过程中所有匹配的 ID
我们要查询数据的顺序如下(示例):
来自交易数据:
- Return 具有匹配 VIN 和城市的所有车辆
如果none存在:
- Return 具有匹配 VIN 的所有车辆
如果none存在:
- Return 具有匹配 Rego 和 City 的所有车辆
这个例子只有三个加宽条件,然而,在我们的应用程序中,它实际上是 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)
但是你的做法是正确的