当表连接到自己时,WHERE子句如何工作?

时间:2012-10-18 15:33:02

标签: sql teradata

我正在重写由Business Objects生成的查询,并使用“老式”隐式连接语法。代码在一个部分中将表连接到自身,并且还具有“global”where子句。例如:

select   a.col1
       , b.col2
from     MYDB.TABLE a, MYDB.TABLE b
where    a.something=b.something_else
     and MYDB.TABLE.source='A'

以上是该问题的简要说明。实际查询很长,加入了大约十个表。

我的问题:如上所述,条件的“额外”是否适用于同一个表的两个实例?我想是的,但我以前从未见过这样的代码。我正在使用Teradata,但我认为这是一个普遍的SQL问题。

更新:也许我尝试缩小问题范围并不准确。这是我想要修改的完整查询:

SELECT
  abs_contrct_prof.contrct_nbr_txt,
  gbs_org_LVL1.bus_pln_sgmnt_cd,
  abs_gnrc_lst_of_val_LVL1.wirls_val_1_txt
FROM
  EDWABSUSERVIEWS.abs_contrct  abs_contrct_prof,
  EDWABSUSERVIEWS.gbs_org  gbs_org_LVL1,
  EDWABSUSERVIEWS.abs_gnrc_lst_of_val  abs_gnrc_lst_of_val_LVL1,
  EDWABSUSERVIEWS.abs_contrct,
  EDWABSUSERVIEWS.gbs_sls_actv_blng_org_rltd,
  EDWABSUSERVIEWS.gbs_sls_actv_org_rltd
WHERE
  ( abs_contrct_prof.type_cd = 'PROFILE'  )
  AND  ( EDWABSUSERVIEWS.abs_contrct.type_cd = 'AGREEMENT'  )
  AND  ( abs_contrct_prof.prnt_contrct_id=EDWABSUSERVIEWS.abs_contrct.contrct_id  )
  AND  ( abs_contrct_prof.org_id=EDWABSUSERVIEWS.gbs_sls_actv_org_rltd.org_id  )
  AND  ( EDWABSUSERVIEWS.gbs_sls_actv_org_rltd.gbs_lvl_3_org_id=EDWABSUSERVIEWS.gbs_sls_actv_blng_org_rltd.gbs_lvl_3_org_id  )
  AND  ( EDWABSUSERVIEWS.gbs_sls_actv_blng_org_rltd.gbs_lvl_1_org_id = gbs_org_LVL1.org_id  )
  AND  ( gbs_org_LVL1.bus_pln_sgmnt_cd=abs_gnrc_lst_of_val_LVL1.nm_txt and abs_gnrc_lst_of_val_LVL1.actv_ind = 'Y' and abs_gnrc_lst_of_val_LVL1.type_cd ='ABS_MOBILITY_SEGMENT'  )
  AND  
  abs_contrct_prof.contrct_nbr_txt  IN  @variable('FAN')
  AND  ( EDWABSUSERVIEWS.abs_contrct.sts_cd = 'Active'  )
  AND  ( EDWABSUSERVIEWS.abs_contrct.type_cd='AGREEMENT'  )

注意表EDWABSUSERVIEWS.abs_contrct在FROM子句中被引用两次,一次使用别名而一次没有。是的,这个查询的工作原理是写的,但我想重写它以使用explict join语法(如有人评论)。

我在查询上运行了一个EXPLAIN,看起来条件(“Active”和“AGREEMENT”)的“额外”实际上分别应用于表的两个实例。

3 个答案:

答案 0 :(得分:4)

  

条件的“额外”是否适用于同一个表的两个实例?

不,它没有。它仅适用于表的一个实例。

另外,查询写得不正确,它应该(并且可能会)在大多数SQL实现中给出错误。您必须命名为ab

select   a.col1
       , b.col2
from     MYDB.TABLE a, MYDB.TABLE b
where    a.something=b.something_else
     and a.source = 'A'                     --or:--   and b.source = 'A'

答案 1 :(得分:3)

如果您的TRANSACTION MODETERADATA,优化程序产品将在WHERE子句中针对包含INNER JOIN结果的假脱机文件加入完全限定的表引用。由于TRANSACTION MODE设置为ANSI,我无法对此进行测试。

示例

CREATE VOLATILE TABLE Test1
    (
        Col1 SMALLINT NOT NULL,
        col2 VARCHAR(10) NOT NULL
    )
    PRIMARY INDEX (Col1)
    ON COMMIT PRESERVE ROWS;

CREATE VOLATILE TABLE Test2
    (
        Col1 SMALLINT NOT NULL,
        col2 VARCHAR(10) NOT NULL
    )
    PRIMARY INDEX (Col1)
    ON COMMIT PRESERVE ROWS;

SELECT A.Col1
     , B.Col2
     , Test1.Col1
  FROM Test1 A
     , Test2 B
 WHERE A.Col1 = B.Col1
   AND Test1.Col1 = 1;

解释 - Teradata模式

  1) First, we do an all-AMPs JOIN step from USER.B by way of a RowHash
     match scan with no residual conditions, which is joined to USER.A
     by way of a RowHash match scan with no residual conditions. 
     USER.B and USER.A are joined using a merge join, with a join
     condition of ("USER.A.Col1 = USER.B.Col1").  The result goes into
     Spool 2 (one-amp), which is redistributed by the hash code of (9)
     to all AMPs.  The size of Spool 2 is estimated with low confidence
     to be 1 row (15 bytes).  The estimated time for this step is 0.02
     seconds. 
  2) Next, we do a single-AMP JOIN step from Spool 2 (Last Use) by way
     of an all-rows scan, which is joined to USER.Test1 by way of the
     primary index "USER.Test1.Col1 = 1" with no residual conditions. 
     Spool 2 and USER.Test1 are joined using a product join, with a
     join condition of ("(1=1)").  The result goes into Spool 1
     (all_amps), which is built locally on that AMP.  The size of Spool
     1 is estimated with low confidence to be 1 row (22 bytes).  The
     estimated time for this step is 0.01 seconds. 
  3) Finally, we send out an END TRANSACTION step to all AMPs involved
     in processing the request.
  -> The contents of Spool 1 are sent back to the user as the result of
     statement 1.  The total estimated time is 0.03 seconds. 

<强>更新

INSERT INTO Test1 VALUES (1,'C');
INSERT INTO Test1 VALUES (2,'D');
INSERT INTO Test2 VALUES (1, 'C1');
INSERT INTO Test2 Values (2, 'D2');

<强>结果

Col1  Col2  Test1.Col1
----++----++----------
1     C1    1
2     D2    1

过滤条件未应用于FROM子句中的表。

答案 2 :(得分:2)

dbms在解析查询时所做的第一件事(就像它一样)是从所有表构造函数(FROM子句,JOIN等)构建工作表。

之后,dbms立即(就像它去的那样)到WHERE子句,并从工作表中删除所有未测试为TRUE的行。

因此有效 WHERE子句适用于工作表中的所有行。早期SQL标准委员会的成员,暴躁的乔·塞尔科(Joe Celko)经常在网上撰写有关order of processing的文章。 (在该链接中搜索有效实现的主题。)