select sc.catName,sc2.catName as pCatName, g.*,shop.shopName,shop.deliveryType,ga.id goodsAttrId,ga.attrPrice,ga.attrStock,shop.shopAtive,shop.shopTel,shop.shopAddress,shop.deliveryTime,shop.isInvoice, shop.deliveryStartMoney,g.goodsStock,shop.deliveryFreeMoney,shop.qqNo,shop.deliveryMoney ,g.goodsSn,shop.serviceStartTime,shop.serviceEndTime FROM tm_goods g left join tm_goods_attributes ga on g.goodsId=ga.goodsId and ga.isRecomm=1, tm_shops shop, tm_shops_cats sc LEFT JOIN tm_shops_cats sc2 ON sc.parentId = sc2.catId WHERE g.goodsId = 某个值(如果这个值来自于网页输入,这样写是不是有注入风险)AND shop.shopId=sc.shopId AND sc.catId=g.shopCatId1 AND g.shopId = shop.shopId AND g.goodsFlag = 1 ";
语句中红色字体为表名。
在开源软件中看到这么一句sql查询,因为对数据库不熟悉,连接类的语句只学过两个表相连加个on条件判断,对于多此连接的语句没有涉及过,所以不了解,有些困惑,请大牛指点。我现在将语句做下面拆分:
第一部分:select sc.catName,sc2.catName as pCatName, g.*,shop.shopName,shop.deliveryType,ga.id goodsAttrId,ga.attrPrice,ga.attrStock,shop.shopAtive,shop.shopTel,shop.shopAddress,shop.deliveryTime,shop.isInvoice, shop.deliveryStartMoney,g.goodsStock,shop.deliveryFreeMoney,shop.qqNo,shop.deliveryMoney ,g.goodsSn,shop.serviceStartTime,shop.serviceEndTime
这里主要是要查询的字段,没有疑议。第二部分:FROM tm_goods g left join tm_goods_attributes ga on g.goodsId=ga.goodsId and ga.isRecomm=1,
这里是第一次两张表的连接加on条件判断。这里有一个疑问,数据执行的时候是先将两张表做一次左连接生成一张临时表,再在临时表中做on条件判断,最后将判断的结果生成一张新表,我可以这样理解吗?第三部分:tm_shops shop, tm_shops_cats sc LEFT JOIN tm_shops_cats sc2 ON sc.parentId = sc2.catId WHERE g.goodsId = 某个值(如果这个值来自于网页输入,这样写是不是有注入风险)AND shop.shopId=sc.shopId AND sc.catId=g.shopCatId1 AND g.shopId = shop.shopId AND g.goodsFlag = 1 ";
这里我就比较晕了,先把我理解的说出来,大牛帮我看看理解的是否正确,tm_shops shop, tm_shops_cats sc这几个字段应该有一个功能是为第一部分提供缩写shop 和sc,不知还有没有其他功能?LEFT JOIN tm_shops_cats sc2 ON sc.parentId = sc2.catId WHERE g.goodsId = 某个值(如果这个值来自于网页输入,这样写是不是有注入风险)AND shop.shopId=sc.shopId AND sc.catId=g.shopCatId1 AND g.shopId = shop.shopId AND g.goodsFlag = 1 ";
这里直接left jion 没有from了, 是不是说将第二部分生成的临时表与这里的 tm_shops_cats 表再做一次左连接?新人求教,大牛支援,非常感谢!

解决方案 »

  1.   

    左连接就是已on后面的条件进行连接的,没有必要看作两部分。tm_shops shop, tm_shops_cats sc这不是字段而是两张表,他们和其他表的关系没有使用显式的join方式而是在where时候进行条件关键,一般来说,执行计划里这两种是等价的,当然也有特殊所以一切要以实际执行计划为准,而且这种方式默认是inner join方式
      

  2.   

    第二部分  LEFT JOIN 关键字会从左表 那里返回所有的行,即使在右表 (table_name2) 中没有匹配的行。
    所以左连接返回的是左表的所有的行。
      

  3.   


    非常感谢你和三位朋友的解答,回答我基本看懂,不过还有一些疑问,为了加深理解,我将长语句做了拆分,分别在数据库中执行,拆分过程如下:第一次拆分:为了语句简洁,去掉了大部分无关查询字段,仅保留少量关键字段
    select g.goodsId, g.goodsName, ga.goodsId, ga.attrVal FROM hm_goods g left join hm_goods_attributes ga on g.goodsId=ga.goodsId;
    这是一个左连接,根据on的条件连接两张表。第二次拆分:添加  ga.isRecomm=1 筛选条件
    select g.goodsId, g.goodsName, ga.goodsId, ga.attrVal FROM hm_goods g left join hm_goods_attributes ga on g.goodsId=ga.goodsId and ga.isRecomm=1;
    这里有一个疑问,筛选条件的作用时机。
    1、在两张表连接之后,使用筛选条件过滤掉不符合的记录。
    2、在两张表连接之前,先使用筛选条件在ga表( hm_goods_attributes)上滤除掉不符合记录再进行连接。
    3、或者数据库会在on连接的同时对筛选条件作出判断,并没有两个过程。
    请教,通常的数据库会按照那种方式执行。第三次拆分:添加多表
    select g.goodsId, g.goodsName, ga.goodsId, ga.attrVal, shop.shopId, shop.shopName, sc.parentId, sc2.catId FROM hm_goods g left join hm_goods_attributes ga on g.goodsId=ga.goodsId and ga.isRecomm=1,
    hm_shops shop, hm_shops_cats sc LEFT JOIN hm_shops_cats sc2 ON sc.parentId = sc2.catId ;
    这条语句,我执行,看执行时间花了0.03x秒
    这里还是有些疑惑,就这条语句本身的执行,是先执行第一个左连接,得到一张临时表A,再让零时表A与hm_shops shop, hm_shops_cats分别做内部连接得到零时表B,零时表B再与hm_shops_cats再做一次左连接。或者我这里理解不对,实际上是别的执行方式。
    这里逻辑有点乱,请帮忙解惑,谢谢!第四次拆分:最后一次了,非常感谢大家的耐心,让我絮叨到这里。
    select g.goodsId, g.goodsName, ga.goodsId, ga.attrVal, shop.shopId, shop.shopName, sc.parentId, sc2.catId FROM hm_goods g left join hm_goods_attributes ga on g.goodsId=ga.goodsId and ga.isRecomm=1,
    hm_shops shop, hm_shops_cats sc LEFT JOIN hm_shops_cats sc2 ON sc.parentId = sc2.catId WHERE g.goodsId = 3 AND shop.shopId=sc.shopId AND sc.catId=g.shopCatId1 AND g.shopId = shop.shopId AND g.goodsFlag = 1;
    这条语句执行了0.001秒,语句本省比第三次拆分还长,居然花的时间比第三次要小一个数量级,唯一的原因是后面的where条件起作用了,烦请大牛详细讲讲,数据库小白先行谢过。楼上三位朋友一并谢过!
      

  4.   

    左联内部具体的执行流程并不为人所知,就如复杂sql的执行顺序一样,都是由sqlserver内部优化后进行的,我们能看到的就是执行计划,对于left join来说一个条件或是两个条件在执行计划中并没有被显示为两个步骤,那么你也可以认为这就是一个过程,或者是同时进行。第二次拆分你理解错了,第一个左联和第一句一样不多解释,第2个左联是两张hm_shops_cats的一个连接,但由于没有where条件,hm_shops shop, hm_shops_cats sc,hm_goods g或hm_goods_attributes ga几张表间并没有写明连接条件,逗号是inner join没错,但如果没有where后面的条件,就相当于无条件的内联,即笛卡尔积本身,所以时间问题也由此引起
      

  5.   

    可以理解为类似于以下的语句Select * from (Select * from t1 a left outer join t2 b on a.id=b.id ) aa,t3 c where aa.id=c.id
    复杂查询要一个个去分解。