SQL查询帮助在哪里条件

时间:2016-11-29 20:30:41

标签: sql sql-server plsql plsqldeveloper sqlcode

我正在处理报告查询,需要显示包含p类型项目和其他非p项目的订单(非P项目包含50个项目),他们需要结合两种类型项目的订单详细信息

以下是我准备的查询,但此查询还显示未与非p项组合的ptype订单。

SELECT
  vwOrD.ONUMBER,
  vwOrD.ITEMID,
  vwITEMs.cat,
  vwITEMs.id
FROM vwITEMs
INNER JOIN vwOrD
  ON vwITEMs.ITEMID = vwOrD.ITEMID
INNER JOIN vwOrders
  ON vwOrD.ONUMBER = vwOrders.ONUMBER
WHERE vwOrders.CUSTID        = 'test'
  AND vwOrders.CREATEDATE >= '1-1-2016'
  AND vwOrders.CREATEDATE <= '11-28-2016'
  AND vwOrD.ONUMBER       IN
  (SELECT vwOrD.ONUMBER
   FROM vwOrD
   INNER JOIN vworders
    ON vwOrD.ONUMBER = vwOrders.ONUMBER
   INNER JOIN vwITEMs
    ON vwITEMs.ASCITEMID = vwOrD.ASCITEMID
    WHERE vwOrders.SOLDTOCUSTID  = 'test'
      AND vwITEMs.cat          = N'PI' -- Pitems cat= pi, id = c
      AND vwITEMs.id           = 'C'
      AND vwOrders.CREATEDATE >= '1-1-2016'
      AND vwOrders.CREATEDATE <= '11-28-2016' --group by          vwOrD.ONUMBER
      -- having count(1) > 1
  )
ORDER BY
  vwOrD.ONUMBER

生成的示例输出:

  ornumber  idnum  categ id  id
        12    xxx        pi   c 
        12    xxx     nonpi   c
        11    yyy        pi   c
        10    qqq        pi   c

预期结果

12 xxx    pi c
12 xxx nonpi c

2 个答案:

答案 0 :(得分:1)

我不确定为什么子查询中的列不同,但我认为这不是你麻烦的根源。

您正在使用子查询来确保对于您要返回的每一行,该订单中的项目都带有'pi'项。这与你说你试图做的有点不同。

下面的查询会返回'pi''nonpi'的行,这些行的onumber也是'pi''nonpi'的另一行,但不是与它正在检查的行相同cat

select 
    d.onumber 
  , d.itemid
  , i.cat
  , i.id 
  from vwitems as i
    inner join vwOrD    as d on i.itemid = d.itemid 
    inner join vwOrders as o on d.onumber = o.onumber 
  where o.custid = 'test' 
    and o.createdate >= '1-1-2016' 
    and o.createdate <= '11-28-2016' 
    and exists (
      select 1 
        from vwOrD
          inner join vwitems on vwitems.ascitemid = vwOrD.ascitemid  /* ascitemid vs itemid ? */
          and vwitems.cat = 'Pi'
          and vwitems.id = 'C' 
          and vwOrD.onumber=o.onumber
          )
    and exists (
      select 1 
        from vwOrD
          inner join vwitems on vwitems.ascitemid = vwOrD.ascitemid  /* ascitemid vs itemid ? */
          and vwitems.cat != 'Pi'
          and vwitems.id = 'C' 
          and vwOrD.onumber=o.onumber
          )
  order by d.onumber;        

答案 1 :(得分:0)

select 
   d.onumber 
  ,d.itemid
  ,i.cat
  ,i.id 
from
    vwitems as i
    inner join vwOrD d
    on i.itemid = d.itemid 
    inner join vwOrders o
    on d.onumber = o.onumber 
    AND o.custid = 'test' 
    and o.createdate >= '1-1-2016' 
    and o.createdate <= '11-28-2016' 
WHERE
    EXISTS (SELECT
             1
          FROM
             vmItems i2
             INNER JOIN vwOrd d2
             ON i2.itemid = d2.itemid
          WHERE
             o.onumber = d2.onumber
          HAVING
             COUNT(DISTINCT i.Cat) > 1
             AND COUNT(CASE WHEN i.Cat = 'Pi' THEN 1 END) > 0)

这应该优于2个单独的EXISTS语句。

此外,您已经加入了所有已加入的表,因此您可以使用带有条件聚合的窗口函数并执行此操作。这是一个Common Table Express [CTE]版本,但它也可以作为派生表放置。这可能会表现得更好:

;WITH cte AS (
    select 
      d.onumber 
     ,d.itemid
     ,i.cat
     ,i.id 
     ,COUNT(CASE WHEN i.Cat = 'Pi' THEN 1 ELSE 0 END) OVER (PARTITION BY o.number) as PiCount
     ,COUNT(CASE WHEN i.Cat <> 'Pi' THEN 1 ELSE 0 END) OVER (PARTITION BY o.number) as NonPiCount
    from
       vwitems as i
       inner join vwOrD d
       on i.itemid = d.itemid 
       inner join vwOrders o
       on d.onumber = o.onumber 
       AND o.custid = 'test' 
       and o.createdate >= '1-1-2016' 
       and o.createdate <= '11-28-2016' 
)

SELECT *
FROM
    cte
WHERE
    PiCount > 0
    AND NonPiCount > 0

由于一个小小的烦恼,我想部分地向你展示这些答案。 您应该在ON条件NOT WHERE子句中放置连接上的约束。当您执行inner join时,您不会注意到任何不同但只要您使用{{1}如果你保留OUTER JOIN子句中的条件,它将成为WHERE。另外,通过限制inner join条件,SQL可以减少它在处理之前处理的记录集,这可能会导致更好的优化。

相关问题