3方式连接子查询和多个where子句

时间:2016-05-24 04:07:14

标签: sql sql-server

我正在尝试解决一个问题,当我运行我的查询时它只是永远运行而且当我有3个where子句时不会执行,但如果我只有2个where子句它执行完全正常。

function array_seaech($array, $search)
    {
        $count = 0;
        foreach($array as $key => $value)
        {
            if(strpos($value, $search))
                $count++;
        }

        return $count;
    }

当我添加SELECT top(1) INV.SUBINVENTORY_CODE, INV.LOCATOR_CODE, INV.ITEM_CODE, dp.DESCRIPTION, dp.barcode1, dp.barcode2, INV.QTY, dp.FROM_SUB_INVENTORY_CODE, dp.FROM_LOCATOR_CODE, INV.SUBINVENTORY_CODE, Inv.INVENTORY_ITEM_ID, dp_hist.barcode1, dp_hist.barcode2, dp_hist.DESCRIPTION,dp_hist.FROM_SUB_INVENTORY_CODE, dp_hist.FROM_LOCATOR_CODE FROM INVENTORY AS INV FULL OUTER JOIN deliveries_picks_hist as dp_hist ON Inv.item_code = dp_hist.item_code FULL OUTER JOIN deliveries_picks AS dp ON dp_hist.item_code = dp.ITEM_CODE WHERE INV.LOCATOR_CODE = 'BMS.S.T.G' and (inv.ITEM_CODE in ((select TOP(1) ITEM_CODE from deliveries_picks_hist where BARCODE1 = '" & barcode & "' or BARCODE2 = '" & barcode & "' or inv.ITEM_CODE = 'ASM.EN.CD'), (select TOP(1) ITEM_CODE from deliveries_picks where BARCODE1 = '" & barcode & "' or BARCODE2 = '" & barcode & "' or inv.ITEM_CODE = 'ASM.EN.CD'))) group by INV.INVENTORY_ITEM_ID, INV.LOCATOR_CODE, INV.ITEM_CODE, INV.QTY, dp_hist.barcode1, dp_hist.barcode2, dp.DESCRIPTION, dp.FROM_LOCATOR_CODE, dp.FROM_SUB_INVENTORY_CODE, INV.SUBINVENTORY_CODE, DP.BARCODE1, DP.BARCODE2, dp_hist.DESCRIPTION, dp_hist.FROM_SUB_INVENTORY_CODE, dp_hist.FROM_LOCATOR_CODE order by dp_hist.DESCRIPTION 时,查询无法正常工作,但如果我要切换其中一个内部联接并保留inv.ITEM_CODE = 'ASM.EN.CD'那么它也可以正常工作,我还没有能够指出问题,我已经重新格式化并尝试了几种不同的方法来工作但不是运气。

3 个答案:

答案 0 :(得分:3)

我相信你想要的就是我在下面所拥有的。无论INV查找是什么,您都希望ITEM_CODEASM.EN.CD等于deliveries_picks*

OR通常会减慢查询速度。但我认为这里放慢速度的原因很可能是因为在子查询中包含额外条件会导致更多行匹配,因为它在外表(INV)上相关。换句话说,当额外条件为真时, all 子查询表中的行将通过过滤器。优化器可能没有制定计划来利用您只想查看“第一个”的事实。

请注意,在这些子查询中使用TOP时没有ORDER BY的情况下,您可能会遇到问题。没有一个真的没有第一排。顺便说一句,你对完全连接的使用对我来说似乎是可疑的,就像所有的分组列一样。如果您可以描述表关系,那么您可以获得更好的查询。最后,这些“条形码”条件可能比@barcode in (BARCODE1, BARCODE2)更简单,因此您不必重复连接。

SELECT TOP 1 
    INV.SUBINVENTORY_CODE, INV.LOCATOR_CODE, INV.ITEM_CODE,
    dp.DESCRIPTION, dp.barcode1, dp.barcode2, INV.QTY,  
    dp.FROM_SUB_INVENTORY_CODE, dp.FROM_LOCATOR_CODE,
    INV.SUBINVENTORY_CODE, Inv.INVENTORY_ITEM_ID, dp_hist.barcode1, 
    dp_hist.barcode2, dp_hist.DESCRIPTION,
    dp_hist.FROM_SUB_INVENTORY_CODE, dp_hist.FROM_LOCATOR_CODE 
FROM 
    INVENTORY AS INV
    FULL OUTER JOIN deliveries_picks_hist AS dp_hist ON Inv.item_code = dp_hist.item_code 
    FULL OUTER JOIN deliveries_picks AS dp ON dp_hist.item_code = dp.ITEM_CODE 
WHERE 
    INV.LOCATOR_CODE = 'BMS.S.T.G'
    AND INV.ITEM_CODE in (
        (
            select TOP 1 ITEM_CODE from deliveries_picks_hist
            where BARCODE1 = '" & barcode & "' or BARCODE2 = '" & barcode & "'
        ),    
        (
            select TOP 1 ITEM_CODE from deliveries_picks
            where BARCODE1 = '" & barcode & "' or BARCODE2 = '" & barcode & "'
        ),
        'ASM.EN.CD'
    )
group by 
    INV.INVENTORY_ITEM_ID, INV.LOCATOR_CODE, INV.ITEM_CODE, INV.QTY,
    dp_hist.barcode1, dp_hist.barcode2, dp.DESCRIPTION, 
    dp.FROM_LOCATOR_CODE,  dp.FROM_SUB_INVENTORY_CODE,
    INV.SUBINVENTORY_CODE, DP.BARCODE1, DP.BARCODE2, dp_hist.DESCRIPTION,
    dp_hist.FROM_SUB_INVENTORY_CODE, dp_hist.FROM_LOCATOR_CODE 
order by 
    dp_hist.DESCRIPTION

如果不起作用,使用CASE应该可以“推迟”子查询的执行:

    AND
    CASE
        WHEN INV.ITEM_CODE = 'ASM.EN.CD' THEN 1
        WHEN INV.ITEM_CODE IN (
            (
                select TOP 1 ITEM_CODE from deliveries_picks_hist
                where BARCODE1 = '" & barcode & "' or BARCODE2 = '" & barcode & "'
            ),    
            (
                select TOP 1 ITEM_CODE from deliveries_picks
                where BARCODE1 = '" & barcode & "' or BARCODE2 = '" & barcode & "'
            )
        ) THEN 1
    END = 1

我的猜测是这是你对连接逻辑的意图:

FROM 
    INVENTORY AS INV LEFT OUTER JOIN (
        deliveries_picks AS dp
        FULL OUTER JOIN
        deliveries_picks_hist AS dp_hist
            ON dp_hist.ITEM_CODE = dp.ITEM_CODE
    )
        ON INV.ITEM_CODE = COALESCE(dp.ITEM_CODE, dp_hist.ITEM_CODE)

通常,当您看到完整加入时,您还会看到一堆COALESCE()次操作。

答案 1 :(得分:1)

我尝试将过滤器构建到连接中。试一试

SELECT TOP(1) INV.subinventory_code, 
              INV.locator_code, 
              INV.item_code, 
              dp.description, 
              dp.barcode1, 
              dp.barcode2, 
              INV.qty, 
              dp.from_sub_inventory_code, 
              dp.from_locator_code, 
              INV.subinventory_code, 
              Inv.inventory_item_id, 
              dp_hist.barcode1, 
              dp_hist.barcode2, 
              dp_hist.description, 
              dp_hist.from_sub_inventory_code, 
              dp_hist.from_locator_code 
FROM   inventory AS INV 
       FULL OUTER JOIN deliveries_picks_hist AS dp_hist 
                    ON Inv.item_code = dp_hist.item_code 
                       AND ( dp_hist.barcode1 = '" & barcode & "' 
                              OR dp_hist.barcode2 = '" & barcode & "'
                              OR inv.item_code = 'ASM.EN.CD' ) 
       FULL OUTER JOIN deliveries_picks AS dp 
                    ON dp_hist.item_code = dp.item_code 
                       AND ( dp.barcode1 = '" & barcode & "' 
                              OR dp.barcode2 = '" & barcode & "'
                              OR inv.item_code = 'ASM.EN.CD' ) 
WHERE  INV.locator_code = 'BMS.S.T.G'  
GROUP  BY INV.inventory_item_id, 
          INV.locator_code, 
          INV.item_code, 
          INV.qty, 
          dp_hist.barcode1, 
          dp_hist.barcode2, 
          dp.description, 
          dp.from_locator_code, 
          dp.from_sub_inventory_code, 
          INV.subinventory_code, 
          DP.barcode1, 
          DP.barcode2, 
          dp_hist.description, 
          dp_hist.from_sub_inventory_code, 
          dp_hist.from_locator_code 
ORDER  BY dp_hist.description 

或者也许在使用CTE

加入之前先过滤表格
WITH hist 
     AS (SELECT * 
         FROM   deliveries_picks_hist dp_hist 
         WHERE  dp_hist.barcode1 = '" & barcode & "' 
                 OR dp_hist.barcode2 = '" & barcode & "'
                 OR dp_hist.item_code = 'ASM.EN.CD'), 
     picks 
     AS (SELECT * 
         FROM   deliveries_picks dp 
         WHERE  dp.barcode1 = '" & barcode & "' 
                 OR dp.barcode2 = '" & barcode & "'
                 OR dp.item_code = 'ASM.EN.CD') 
SELECT TOP(1) INV.subinventory_code, 
              INV.locator_code, 
              INV.item_code, 
              dp.description, 
              dp.barcode1, 
              dp.barcode2, 
              INV.qty, 
              dp.from_sub_inventory_code, 
              dp.from_locator_code, 
              INV.subinventory_code, 
              Inv.inventory_item_id, 
              dp_hist.barcode1, 
              dp_hist.barcode2, 
              dp_hist.description, 
              dp_hist.from_sub_inventory_code, 
              dp_hist.from_locator_code 
FROM   inventory AS INV 
       FULL OUTER JOIN hist AS dp_hist 
                    ON Inv.item_code = dp_hist.item_code 
       FULL OUTER JOIN picks AS dp 
                    ON dp_hist.item_code = dp.item_code 
WHERE  INV.locator_code = 'BMS.S.T.G' 
       AND inv.item_code = 'ASM.EN.CD' 
GROUP  BY INV.inventory_item_id, 
          INV.locator_code, 
          INV.item_code, 
          INV.qty, 
          dp_hist.barcode1, 
          dp_hist.barcode2, 
          dp.description, 
          dp.from_locator_code, 
          dp.from_sub_inventory_code, 
          INV.subinventory_code, 
          DP.barcode1, 
          DP.barcode2, 
          dp_hist.description, 
          dp_hist.from_sub_inventory_code, 
          dp_hist.from_locator_code 
ORDER  BY dp_hist.description 

答案 2 :(得分:0)

@Michael Z

这是一个很好的例子

 SELECT TOP(1) INV.subinventory_code,
          INV.locator_code,
          INV.item_code,
          dp.description,
          dp.barcode1,
          dp.barcode2,
          INV.qty,
          dp.from_sub_inventory_code,
          dp.from_locator_code,
          INV.subinventory_code,
          Inv.inventory_item_id,
          dp_hist.barcode1,
          dp_hist.barcode2,
          dp_hist.description,
          dp_hist.from_sub_inventory_code,
          dp_hist.from_locator_code
FROM   inventory AS INV
   FULL OUTER JOIN deliveries_picks_hist AS dp_hist
                ON Inv.item_code = dp_hist.item_code
   FULL OUTER JOIN deliveries_picks AS dp
                ON inv.item_code = dp.item_code
WHERE  INV.locator_code = 'BMS.S.T.G'
   AND ( inv.item_code = (SELECT TOP(1) item_code
                          FROM   deliveries_picks_hist
                          WHERE  barcode1 = ''
                                  OR barcode2 = '')
          OR inv.item_code = 'ASM.EN.CD' )
GROUP  BY INV.inventory_item_id,
      INV.locator_code,
      INV.item_code,
      INV.qty,
      dp_hist.barcode1,
      dp_hist.barcode2,
      dp.description,
      dp.from_locator_code,
      dp.from_sub_inventory_code,
      INV.subinventory_code,
      DP.barcode1,
      DP.barcode2,
      dp_hist.description,
      dp_hist.from_sub_inventory_code,
      dp_hist.from_locator_code
ORDER  BY Max(dp.createtime) DESC 

这样做

   SELECT TOP(1) INV.subinventory_code, 
          INV.locator_code, 
          INV.item_code, 
          dp.description, 
          dp.barcode1, 
          dp.barcode2, 
          INV.qty, 
          dp.from_sub_inventory_code, 
          dp.from_locator_code, 
          INV.subinventory_code, 
          Inv.inventory_item_id, 
          dp_hist.barcode1, 
          dp_hist.barcode2, 
          dp_hist.description, 
          dp_hist.from_sub_inventory_code, 
          dp_hist.from_locator_code 
FROM   inventory AS INV 
   FULL OUTER JOIN deliveries_picks_hist AS dp_hist 
                ON Inv.item_code = dp_hist.item_code 
   FULL OUTER JOIN deliveries_picks AS dp 
                ON dp_hist.item_code = dp.item_code 
WHERE  INV.locator_code = 'BMS.S.T.G' 
   AND ( inv.item_code IN (SELECT TOP(1) item_code 
                           FROM   deliveries_picks_hist 
                           WHERE  barcode1 = '" & barcode & "' 
                                   OR barcode2 = '" & barcode & "' 
                           UNION ALL 
                           SELECT TOP(1) item_code 
                           FROM   deliveries_picks 
                           WHERE  barcode1 = '" & barcode & "' 
                                   OR barcode2 = '" & barcode & "') ) 
GROUP  BY INV.inventory_item_id, 
      INV.locator_code, 
      INV.item_code, 
      INV.qty, 
      dp_hist.barcode1, 
      dp_hist.barcode2, 
      dp.description, 
      dp.from_locator_code, 
      dp.from_sub_inventory_code, 
      INV.subinventory_code, 
      DP.barcode1, 
      DP.barcode2, 
      dp_hist.description, 
      dp_hist.from_sub_inventory_code, 
      dp_hist.from_locator_code 
ORDER  BY dp_hist.description 

有什么建议吗?