【问题标题】:SQL query help in where condition在 where 条件下的 SQL 查询帮助
【发布时间】:2017-04-14 00:02:12
【问题描述】:

我正在处理一个报告查询,它需要显示包含 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

【问题讨论】:

标签: sql sql-server plsql plsqldeveloper


【解决方案1】:
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 时,您不会注意到任何不同,但只要您使用 OUTER JOIN,如果您保持WHERE 子句中的条件将变为inner join。另外,通过限制ON 条件,SQL 可以减少它在必须加入之前处理的记录集,这可能会导致更好的优化。

【讨论】:

    【解决方案2】:

    我不确定为什么您的子查询中的列不同,但我认为这不是您问题的根源。

    您正在使用您的子查询来确保对于您要返回的每一行,在该顺序中都有一个带有'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;        
    

    【讨论】:

    • 嗨,我对超过 50 个不同类别的非 p 项目类型有疑问(除了 p 类型项目被视为不同类别),因此我无法在运算符中使用。
    • 我想我明白你的意思,我已经更新了查询。
    • 这真的应该在一个 EXISTS 语句中完成,而不是 2
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-20
    相关资源
    最近更新 更多