SQL查询建议(替换为连接存在)

时间:2013-08-15 08:05:36

标签: mysql sql join exists

我有以下字段和索引的表:enter image description here
我需要进行一个查询:

  

检查表,如果有拨号事件,之后(使用相同的话)   unique_id)没有 Bridge Hangup 事件

  

如果有 NewCallerId 事件,其后没有挂断事件(具有相同的unique_id)或没有拨打事件(call_id = current) UNIQUE_ID)

有一个查询,但我没有让它工作,用户的答案也没有帮助。 这是在395秒(太长时间)内完成工作的查询:

SELECT t1.* 
FROM   ASTERISK t1 
WHERE  EXISTS (SELECT t2.* 
               FROM   ASTERISK t2 
               WHERE  t1.OPERATOR_DIAL = '$extension' 
                      AND t1.EVENT = 'Dial' 
                      AND NOT EXISTS (SELECT t3.* 
                                      FROM   ASTERISK t3 
                                      WHERE  t3.UNIQUE_ID = t1.UNIQUE_ID 
                                             AND ( t3.EVENT = 'Hangup' 
                                                    OR t3.EVENT = 'Bridge' ))) 
        OR EXISTS (SELECT t4.* 
                   FROM   ASTERISK t4 
                   WHERE  t1.EVENT = 'NewCallerid' 
                          AND t1.OPERATOR_DIAL = '$extension' 
                          AND NOT EXISTS (SELECT t5.* 
                                          FROM   ASTERISK t5 
                                          WHERE  ( t5.UNIQUE_ID = t1.UNIQUE_ID 
                                                   AND t5.EVENT = 'Hangup' ) 
                                                  OR ( t5.CALL_ID = t1.UNIQUE_ID 
                                                       AND t5.EVENT = 'Dial' ))) 
ORDER  BY DATE DESC 
LIMIT  1 

试图用JOINS重写它,但是获取#1248 - 每个派生表必须有自己的别名

这是我尝试使用JOIN查询:

SELECT t1.*
                    FROM asterisk t1
                    INNER JOIN (SELECT t2.* FROM asterisk t2
                                  WHERE
                                    t1.operator_dial = '$extension'
                                  AND t1.event = 'Dial'
                                  LEFT OUTER JOIN (SELECT t3.* FROM asterisk t3
                                                  WHERE t3.unique_id = t1.unique_id AND (t3.event = 'Hangup' OR t3.event = 'Bridge')))
                          OUTER JOIN (SELECT t4.* FROM asterisk t4
                                    WHERE t1.event = 'NewCallerid'
                                    AND t1.operator_dial = '$extension'
                                    LEFT OUTER JOIN (SELECT t5.* FROM asterisk t5
                                                    WHERE (t5.unique_id = t1.unique_id AND t5.event = 'Hangup') OR (t5.call_id = t1.unique_id AND t5.event = 'Dial')))
                    ORDER BY DATE DESC
                    LIMIT 1

要显示查询应该如何工作我制作了2个屏幕截图(顶部部分有一些调用不在查询结果中,而底部部分是一个调用必须在查询结果中:screen

2 个答案:

答案 0 :(得分:1)

我刚开始在堆栈交换上发帖。在没有深入潜水的情况下,我注意到t2和t4的内部连接没有与t1中的任何值匹配的值(可能是原始查询如此长的原因)。

旧查询已删除.......

感谢屏幕截图,这有帮助。那么你希望你的查询返回的是活动调用(没有'hang-ups'或'Bridges'的调用)然后你想要没有相关拨号事件的NewcallerID事件和最后用桥接器拨打事件但是他们之后没有桥梁

SELECT * 
FROM Asterisk t1
WHERE t1.unique_id not in 
    (Select unique_id 
       from Asterisk t2
        Where event = 'Hangup', 'Bridge')
UNION
select *
from asterisk t3
Where event = 'NewCallerID'
    and t3.unique_id not in
      (Select unique_id 
       from Asterisk t4
        Where event = 'Dial')
UNION
Select distinct *
from asterisk t5
    inner join asterisk t6
        on t5.unique_ID = t6.Unique_id
            and t6.event = 'Dial'
Where t5.event = 'Bridge'
         and t6.id > t5.id

我想我已经涵盖了所有案例。 (但闻起来有点hackish)。 编辑:在未覆盖拨号之前存在桥的事件

答案 1 :(得分:1)

我认为你过度复杂了。通过t2别名存在而没有连接 在唯一ID上,您将获得笛卡尔结果。

我内联评论了这个查询,所以一定要在运行之前把它们拿出去。

SELECT 
      t1.*
   FROM   
      ASTERISK t1
         LEFT JOIN ASTERISK t2 
            ON t1.Unique_ID = t2.Unique_ID
            AND ( t2.Event = 'Hangup' 
               OR t2.Event = 'Bridge' )

         LEFT JOIN ASTERISK t3
            ON t1.unique_id = t3.unique_id
            AND t3.EVENT = 'Hangup'

         LEFT JOIN ASTERISK t4
            ON t1.unique_id = t4.call_id
            AND t4.EVENT = 'Dial'
   WHERE
      -- THESE ARE THE PRIMARY CONDITIONS YOU WANT...
      -- a specific operator extension and looking for
      -- either a dial or newcallerid
          t1.OPERATOR_DIAL = '$extension' 
      AND (    t1.EVENT = 'Dial' 
            OR t1.EVENT = 'NewCallerID' ) 

      AND (   
              -- if an outgoing DIAL, you are concerned with 
              -- alias t2 and NOT having any hangup or bridge
              (    t1.EVENT = 'Dial' 
               AND t2.Unique_ID IS NULL )
           OR 
              -- its from the NewCallerID record via t1 alias
              -- and you do not want hangup or dial based on 
              -- the unique ID vs Call ID respectively to the
              -- t3 and t4 aliases
              (    t1.EVENT = 'NewCallerID'
               AND t3.Unique_ID IS NULL
               AND t4.Unique_ID IS NULL )
          )
  ORDER BY 
     t1.`DATE` DESC 
  LIMIT  1 

REVISION基于样本数据,但NewCallerID样本数据除外......

这应该极其简化你所拥有的 - 至少对于出站呼叫。没有显示“NewCallerID”的数据,因此如果没有更好的样本数据,我无法应用该答案。

无论如何,我更改为预先查询给定运营商扩展的所有调用,并根据每个调用的唯一ID分组的呼叫数据记录中的明显自动增量ID列创建第一个和最后一个事件。从那以后,它直接连接到每个表,这样我们就可以看到调用是如何开始的以及它的最后一个活动。从那里,它是一个简单的where子句,最后一个事件仍处于“newstate”设置。如果还有其他设置,例如暂停,电话会议,等等,则需要将其调整为NOT(挂断或桥接)状态......

SELECT
      PerCallSummary.*,
      StartCall.event as BeginEvent,
      StartCall.id as BeginEventID,
      LastCall.event as EndEvent,
      LastCall.id as EndEventID
   from
      ( SELECT 
              t1.unique_id, 
              t1.id beginCall, 
              MAX(t2.id) as lastActivity
           from 
              asterisk t1
                 join asterisk t2
                   on t1.unique_id = t2.unique_id
           where 
                 t1.operator_dial = '$extension'
             and t1.event = 'Dial'
           group by
              t1.unique_id,
              t1.id ) as PerCallSummary
      JOIN Asterisk as StartCall
         ON PerCallSummary.beginCall = StartCall.id
      JOIN Asterisk as LastCall
         ON PerCallSummary.lastActivity = LastCall.id
   where
      LastCall.Event = 'Newstate'

调整内部“PerCallSummary”查询

我认为这会解决这个问题......你没有得到结果的原因是我错误地将你的数据解释为只是简要介绍它的内容,因为operator_dial值没有转发到每条记录。因此,现在调整内部查询以加入星号AGAIN,但仅限于呼叫的unique_id(因为操作员拨号会失败,否则他们没有被填写)。因此,调用将始终与第一个t1记录BEGIN,所以我只是将其作为基础,但现在只有t2记录ID的MAX()...现在,您应该得到正确的结果以继续此操作。 / p>

无论如何,获取一些“NewCallerID”看起来像的示例数据,我们可以调整它以包含它和它的结束标准。