我经常需要在多个表中搜索给定值的精确或类似匹配。 SELECT
语句总是相同的,但我搜索的值总是不同的。
SELECT * FROM employees WHERE first_name = 'foobar';
SELECT * FROM jobs WHERE job_title LIKE 'foobar%';
SELECT * FROM departments WHERE department_name LIKE '%foobar';
SELECT * FROM locations WHERE city LIKE '%foobar%';
我不想创建一个VIEW
或SELECT
(与UNION
),因为我只想执行每个查询,直到找到第一个结果。如果我找到了结果,请停止,以免造成不必要的执行开销。
如何使用PL / SQL传递参数并循环遍历这些语句?嵌套异常块?
在我的环境中,我希望只在一个表中找到结果,或者根本没有结果。我的数据库是Oracle 10g(备用我),我正在使用SQL Developer 4.1.5。
1.
COALESCE()
是Oracle标准函数,Oracle按照标准的要求实现。该函数接受一个或多个参数,所有相同的数据类型(否则解析器将抛出错误),并返回第一个非NULL参数,如果所有参数都为NULL,则返回NULL。
重要的是,查询引擎将计算第一个参数,如果它不是NULL,它将返回它并且它不会计算其他参数。如果第一个参数为NULL但第二个参数不是,它将返回第二个参数,它将停止。这被称为“短路评估”。
2.
标量子查询是一个返回单个列和单个行的查询(如果它返回多行,它应该是标量查询,您将收到运行时错误) - 或者它可能不返回任何行。标量子查询通常用于通常可以使用“表达式”的地方;在这些情况下,子查询返回的一行一列的值将用作所需的“表达式”。如果返回的“value”为NULL,或者子查询未返回任何行,则表达式将为NULL。
3.
您可以使用这些观察来解决您的问题。但是警告:你说你的“搜索”参数只能在一个表中找到。如果在一个表中找到它,但是你必须提取的相应值是NULL,那么COALESCE将不知道应该是搜索的结束,并且它仍将计算所有标量子查询。
以下是使用此想法的示例。由于我没有你的表,我为SCOTT模式中的EMP和DEPT表编写了它。输入是一个数字,我对它进行了硬编码,但你可以使它成为一个绑定变量(你可以编写更复杂的WHERE子句)。我搜索员工编号为10的员工姓名,如果没有找到,我想要部门编号为10的部门名称。
select coalesce (
(select ename from emp where empno = 10),
(select dname from dept where deptno = 10)
) as name from dual;
NAME
--------------
ACCOUNTING
SQL查询返回一组固定的列。因此,您的结构假设所有表都具有相同的列。我怀疑这是实际情况,所以让我假设您知道这一点,并且您使用SELECT *
作为速记。
您不能短路SQL查询。但是,你可以安排它们,所以基本上什么都没做。我们的想法是以步进方式使用NOT EXISTS
。当底层表有数据时,这应该非常快,因此实际上跳过了CTE逻辑。
这是一种使用CTE的方法
with e as (
SELECT *
FROM employees
WHERE first_name = 'foobar'
),
j as (
SELECT *
FROM jobs
WHERE job_title LIKE 'foobar%' AND
NOT EXISTS (SELECT 1 FROM e)
),
d as (
SELECT *
FROM departments
WHERE department_name LIKE '%foobar' AND
NOT EXISTS (SELECT 1 FROM e) AND
NOT EXISTS (SELECT 1 FROM j)
),
l as (
SELECT *
FROM locations WHERE city LIKE '%foobar%' AND
NOT EXISTS (SELECT 1 FROM e) AND
NOT EXISTS (SELECT 1 FROM j) AND
NOT EXISTS (SELECT 1 FROM d)
)
SELECT e.* FROM e UNION ALL
SELECT j.* FROM j UNION ALL
SELECT d.* FROM e UNION ALL
SELECT l.* FROM l ;