我有一个表products
和一个表translations
。我为每种产品提供了n
个翻译,但始终至少有一个默认翻译(LangID = 0
)。
我想要做的是"搜索查询"用户输入的字符串。如果用户使用的语言中有翻译(让我们说LangID = 1
)我只想搜索此语言的翻译(也不是默认翻译),但是如果没有翻译我希望在默认翻译中搜索所需的语言。所以基本上默认的翻译只是一个后备。
我想出了什么:
SELECT * FROM products p JOIN translations t ON p.ID = t.ProductID
WHERE (t.LangID = 1 OR (t.LangID = 0 AND NOT EXISTS (SELECT id FROM translations t2 WHERE t2.ProductID = p.ID AND t2.LangID = 1))
AND t.Translation LIKE "Foo%" `
这是最好的方法还是没有嵌套选择可以做到这一点?或者是否有更好的(表现明智的)查询/方法?
答案 0 :(得分:2)
你可以这样做,但不清楚执行计划是好还是不好坏。 OR
和EXISTS
的组合无法可靠地产生良好的计划。
加入两次更安全,更快:
select *
from products p
left join translations t1 on t1.langid = 1 and ...
left join translations t0 on t1.langid is null and t0.langid = 0 and ...
然后使用t1
的值(如果存在)。如果不是,请使用t0
的值。谓词t1.langid is null
是可选的,但它允许SQL Server(希望)在第一个连接成功的情况下跳过第二个连接。我已经看到这种模式有效,但假设它总是这样做是不安全的。
这导致了一个可靠而简单的计划。
答案 1 :(得分:1)
with t as (
SELECT * FROM products p JOIN translations t ON p.ID = t.ProductID
WHERE t.LangID = 1 AND t.Translation LIKE "Foo%")
select * from t
union all
SELECT * FROM products p, translations t
where (select count(*) from t) = 0
and p.ID = t.ProductID
and t.LangID = 0 AND t.Translation LIKE "Foo%"';
它是Oracle语法, t 只是一个子查询(WITH允许您为子查询指定名称)
如果计算 t 的过程很复杂,此查询可能会更快
P.S。您的数据库可能不会对WHERE条件使用快捷方式评估。需要测试(实际上Oracle并不保证其使用,但Oracle优化器足够智能,所以它适用于我的情况)