【发布时间】:2016-03-06 04:08:07
【问题描述】:
假设我们有一个汽车经销商网站,可以搜索品牌、型号、类型和年份。完整的搜索词应为 Toyota Corolla Sedan 2006。 “Toyota”在 Cars 主表中由一个简单的数字 ID 键表示,“Corolla”和“Sedan”也是如此。 Make、Model 和 Sedan 的键引用 Makes、Models 和 Car_Types 表。
查询应该首先返回完全匹配,即。从 2006 年开始是 Toyota Corollas 的所有汽车。然后,相同的查询应该从 2006 年以外的年份返回 Corollas,按相关性降序排列,因此首先是接近 2006 年的年份,然后是更远的年份,然后它会返回其他丰田汽车那不是卡罗拉,而是轿车,最后是其他既不是卡罗拉也不是轿车的丰田。
使用基于搜索参数的 UNION 编写多阶段动态 SQL 查询是可以容忍的(如果很麻烦的话),但我不禁觉得有一种优雅的一步一步的方法可以做到这一点。当然,如果没有更好、更明智的方法,那么我可能最终会采用 UNION 方法:
SELECT * FROM (
SELECT Car_ID, 1 as ResultOrder FROM Cars
WHERE Make_ID = 1 AND Model_ID = 5 AND Car_Type_ID = 7 AND Year = 2006
UNION
SELECT Car_ID, 2 as ResultOrder FROM Cars
WHERE Make_ID = 1 AND Model_ID = 5 AND Car_Type_ID = 7
UNION
SELECT Car_ID, 3 as ResultOrder FROM Cars
WHERE Make_ID = 1 AND Car_Type_ID = 7
UNION
SELECT Car_ID, 4 as ResultOrder FROM Cars
WHERE Make_ID = 1
) AS Results
ORDER BY ResultOrder
感觉很笨重。这是不雅的。如果你能建议一个更健全、更高效的方法,我会全力以赴。感谢您的宝贵时间!
【问题讨论】:
-
如果您在 where 子句中使用了一个包含所有逻辑的 case 语句,并且每个字段的检查都不为空,该怎么办。如果它们都不为空,则 ResultOrder = 1,如果四个中的三个不为空,则为 2,等等...我建议类似于 sgeddes 但不是检查下面的值,而是检查它们是否'不为空。如果它们都不为空,它会找到一个完全匹配的,等等。
-
如果您想通过单选运行它,您至少需要几个固定/非可选过滤条件才能使其表现良好。因为所有其他条件都是可选的 - 太多的
ORs 只意味着scan。 -
谢天谢地,我们处理的是数百条记录,而不是数千条或数百万条记录,因此性能存在自然限制。如果经销商突然增长,他们就有足够的钱来解决问题;)但我当然同意你的观点。
标签: sql sql-server union