Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 影响连接的Where子句_Sql_Oracle_Oracle10g - Fatal编程技术网

Sql 影响连接的Where子句

Sql 影响连接的Where子句,sql,oracle,oracle10g,Sql,Oracle,Oracle10g,愚蠢的提问时间。甲骨文10g where子句是否可能影响联接 我有一个如下形式的查询: select * from (select product, product_name from products p join product_serial ps on product.id = ps.id join product_data pd on pd.product_value = to_number(p.product_value)) product_result where product_n

愚蠢的提问时间。甲骨文10g

where子句是否可能影响联接

我有一个如下形式的查询:

select * from
(select product, product_name from products p
join product_serial ps on product.id = ps.id
join product_data pd on pd.product_value = to_number(p.product_value)) product_result
where product_name like '%prototype%';
显然,这是一个人为的例子。不需要显示表结构,因为它都是虚构的。不幸的是,我不能显示真正的表结构或查询。在本例中,p.product_值是一个VARCHAR2字段,它在某些行中存储了一个ID,而不是文本。(是的,糟糕的设计——但我继承了一些东西,无法改变)

问题在于联合。如果省略where子句,则查询有效并返回行。但是,如果我添加where子句,在pd.product\u value=to\u number(p.product\u value)连接条件上会出现“invalid number”错误

显然,当p.product_值字段中包含非数字的行被合并时,会发生“无效数字”错误。但是,我的问题是如何选择这些行?如果连接成功而没有外部where子句,那么外部where子句不应该只从连接结果中选择行吗?似乎发生的事情是where子句正在影响连接的行,尽管连接在内部查询中


我的问题有意义吗?

我想您的
to\u编号(p.product\u值)
仅适用于具有有效
产品名称的行

发生的情况是,在
where
子句之前应用了
join
,导致
to_number
函数失败

您需要做的是将您的
产品名称(如“%prototype%”)作为
JOIN
子句包括在内,如下所示:

select * from
(select product, product_name from products p
join product_serial ps on product.id = ps.id
join product_data pd on product_name like '%prototype%' AND
     pd.product_value = to_number(p.product_value));

它会影响生成的计划

表的实际连接顺序(以及过滤顺序)不是由您编写查询的顺序决定的,而是由表上的统计信息决定的

在一个版本中,附带生成的计划意味着“坏”行永远不会得到处理;因为前面的连接将结果集过滤到一个从未连接的点

WHERE
子句的引入意味着ORACLE现在认为不同的联接顺序更好(因为按产品名称过滤需要特定的索引,或者因为它将数据缩小了很多,等等)

这个新的顺序意味着“坏”行在过滤掉它们的联接之前得到处理


在查询之前,我会尽力清理数据。可能通过创建一个派生列,其中的值已转换为数字,或者如果无法转换,则保留为NULL

您还可以使用“解释计划”查看查询中生成的不同计划。

简短回答:是

长答案:查询引擎可以随意重写查询,只要返回相同的结果。它可以使用所有查询来生成最高效的查询

在这种情况下,我猜有一个索引包含了您想要的内容,但它不包含产品名称,当您将其添加到where子句中时,该索引不被使用,而是在扫描中同时测试两个条件,从而导致您的错误

这在您的加入条件中确实是一个错误,您不应该使用to_number,除非您确定它是一个数字。

有关更多背景信息(以及非常好的阅读),我建议阅读Jonathan Gennick的

基本上,问题在于Oracle可以自由地以任何顺序计算谓词。因此,可以自由地将
product\u name
谓词推(或不推)到子查询中。可以按任意顺序计算联接条件。因此,如果Oracle碰巧选择了一个查询计划,在将
应用于
编号之前过滤掉非数字的
产品_值
行,则查询将成功。如果在筛选出非数字的
产品\u值
行之前,选择了一个将
应用于\u编号
的计划,您将得到一个错误。当然,它也可能会成功返回前N行,然后在尝试获取第N+1行时会出现错误,因为第N+1行是它第一次尝试将
to_number
谓词应用于非数字数据


除了修复数据模型之外,您还可以向查询中添加一些提示,强制Oracle计算谓词,以确保在应用
to_number
谓词之前过滤掉所有非数字数据。但一般来说,以一种迫使优化器总是以“正确”的顺序计算事物的方式完全提示查询有点困难。

您可以给它一点空闲时间
(pd.product\u值)=p.product_value
。这可能有帮助,也可能没有帮助-没有任何东西可以阻止Oracle尝试首先计算
to_编号