当只改变字段,值时,oracle为两个相同的查询产生不同的结果

时间:2016-09-02 07:34:18

标签: oracle plsql oracle-sqldeveloper

我有SQL查询。当我声明变量并运行查询时,它会生成39行,但是当我使用文字值而不是变量并运行查询时,它会产生三行。怎么会这样?

以下是带变量的查询和结果

declare 
    fromnode number :=1;
    CURRENTESTIMATE number :=0;
begin
  for ts in (SELECT  e.fromnode,e.tonode,e.weight
      FROM TS_DIJNODEESTIMATE N 
      INNER JOIN TS_EDGE E ON N.ID=E.TONODE
      WHERE N.DONE=0 AND E.FROMNODE=fromnode  AND (CURRENTESTIMATE+E.WEIGHT)<N.ESTIMATE)
      loop
        dbms_output.put_line(ts.fromnode || ',' || ts.tonode || ',' || ts.weight);
      end loop;

end;

结果是

1,2,1306
1,5,2161
1,6,2661
2,3,919
2,4,629
3,2,919
3,4,435
3,5,1225
3,7,1983
4,2,629
4,3,435
5,3,1225
5,6,1483
5,7,1258
6,5,1483
6,7,1532
6,8,661
7,3,1983
7,5,1258
7,6,1532
7,9,2113
7,12,2161
8,6,661
8,9,1145
8,10,1613
9,7,2113
9,8,1145
9,10,725
9,11,383
9,12,1709
10,8,1613
10,9,725
10,11,338
11,9,383
11,10,338
11,12,2145
12,7,2161
12,9,1709
12,11,2145

使用文字而不是变量:

declare 
    fromnode number :=1;
    CURRENTESTIMATE number :=0;
begin
  for ts in (SELECT  e.fromnode,e.tonode,e.weight
      FROM TS_DIJNODEESTIMATE N 
      INNER JOIN TS_EDGE E ON N.ID=E.TONODE
      WHERE N.DONE=0 AND E.FROMNODE=1  AND (0+E.WEIGHT)<N.ESTIMATE)
      loop
        dbms_output.put_line(ts.fromnode || ',' || ts.tonode || ',' || ts.weight);
      end loop;

end;

结果是

1,2,1306
1,5,2161
1,6,2661

期望的结果是第二个结果。

2 个答案:

答案 0 :(得分:2)

您应该将变量fromnode的名称更改为my_fromnode或类似名称。

E.FROMNODE=fromnode实际上将列与本身进行比较并返回true的内部查询中。

答案 1 :(得分:1)

问题在于命名:您为变量提供了与表列相同的名称:

E.FROMNODE=fromnode

Oracle的范围规则使用最近的匹配来解析名称,从最里面开始,向外和向上工作。查询中最近的命名空间是表,因此它首先尝试将fromnode解析为表列。名称适合,因此编译器不再进一步查看。

有效地,您的WHERE子句过滤器在逻辑上与1 = 1相同,这就是为什么您获得更多行的原因。这不应该是一个惊喜,因为它是记录的行为。 PL / SQL文档涵盖了变量标识符名称here的范围以及与变量名here的交互。关键点是Alex Poole的亮点:

  

&#34;如果SQL语句引用属于列和局部变量或形式参数的名称,则列名优先。&#34;

您认为通过将fromnode置于小写但PL / SQL不区分大小写的情况下避免了这种情况。正确的方法是使用命名约定,例如标识带有前缀的变量:V表示变量 - v_fromnode - 或L表示本地 - l_fromnode - 都是常见约定。