Php 确定发帖间隔时间的有效方法?

Php 确定发帖间隔时间的有效方法?,php,sql,postgresql,Php,Sql,Postgresql,我得到了一个场景,我希望如果有一种更有效的方法来优化代码,我们开始吧 假设有一个名为ticket\u thread的表,其中包含以下字段 线状 ticketID 螺纹类型-可以是c2s、s2s、s2c postTime-日期时间 消息 所有数据都是按ticketID排序的,然后是postTime 我的工作是确定每个c2s到s2c所需的时间,即响应时间 我当前的方法是将过滤后的表转储到两个列表中—c2s和s2c while (!isempty($c2s) || !isempty($s2c)) {

我得到了一个场景,我希望如果有一种更有效的方法来优化代码,我们开始吧

假设有一个名为ticket\u thread的表,其中包含以下字段

线状 ticketID 螺纹类型-可以是c2s、s2s、s2c postTime-日期时间 消息 所有数据都是按ticketID排序的,然后是postTime

我的工作是确定每个c2s到s2c所需的时间,即响应时间

我当前的方法是将过滤后的表转储到两个列表中—c2s和s2c

while (!isempty($c2s) || !isempty($s2c)) {

  // popping first record from c2s
  $c2sRecord = array_shift($c2s);

  if (!$c2sRecord['ticketID'] == $s2c[0]['ticketID']) {

    // cannot find a response to the ticket
    echo $c2sRecord['ticketID'] . "<br>";

  } else {

    echo $c2sRecord['ticketID'];

    // popping first response from s2c
    $s2cRecord = array_shift($s2c);

    // print out the response time
    echo " " . date_diff($s2cRecord['postTime'], $c2sRecord['postTime']);

    $filter = true;
    while ($filter) {

      // checking the next record in c2s, if it is a different ticket 
      // OR the new post is placed AFTER service has responded.
      if (($c2s[0]['ticketID'] <> $s2cRecord['ticketID']) 
          or ($c2s[0]['postTime'] > $s2cRecord['postTime'])) {

        // stops the filter
        $filter = false;

      } else {

        // pop out unneeded records (supplementary questions) 
        $c2sRecord = array_shift($c2s);

      }
    }
  }
编辑:根据要求编辑样本表


如果所有人都能像基于聚合的变体那样支持FILTER子句,那么您的任务可能会简单得多。也就是说,您只需要:

-不幸的是,这行不通 第一个时间过滤器,其中线程类型='s2c' 按票证id进行过分区 邮购 当前行和无界后续行之间的行 在此之前,您可以使用自联接:

select  t.*, row_number() over (partition by t.ticket_id order by t.c2s_time) rank
from    (select    distinct on (coalesce(s2c.thread_id, c2s.thread_id))
                   c2s.ticket_id,
                   c2s.post_time c2s_time,
                   c2s.message c2s_message,
                   s2c.post_time s2c_time,
                   s2c.message s2c_message,
                   s2c.post_time - c2s.post_time time_taken
         from      ticket_thread c2s
         left join ticket_thread s2c on  c2s.ticket_id = s2c.ticket_id
                                     and s2c.thread_type = 's2c'
                                     and c2s.post_time < s2c.post_time
                                     and not exists(select 1
                                                    from   ticket_thread
                                                    where  post_time > c2s.post_time
                                                    and    post_time < s2c.post_time
                                                    and    ticket_id = c2s.ticket_id
                                                    and    thread_type = 's2c')
         where     c2s.thread_type = 'c2s'
         order by  coalesce(s2c.thread_id, c2s.thread_id), c2s.post_time) t
order by t.ticket_id, t.c2s_time;
从我的内部测试来看,self-join变体似乎要快一点&它还可以在ticket\u id、post\u time上使用索引。但是,如果性能对您来说真的很重要,您应该同时测试这两个方面

或者,您也可以添加缺少的功能,即创建第一个聚合并将其用作窗口函数:

select  t.*, row_number() over (partition by t.ticket_id order by t.c2s_time) rank
from    (select    distinct on (coalesce((m).thread_id, (t).thread_id))
                   (t).ticket_id,
                   (t).post_time c2s_time,
                   (t).message c2s_message,
                   (m).post_time s2c_time,
                   (m).message s2c_message,
                   (m).post_time - (t).post_time time_taken
         from      (select t, array_agg(t) filter (where thread_type = 's2c')
                                             over (partition by ticket_id
                                                   order by     post_time
                                                   rows between current row and unbounded following) a
                    from   ticket_thread t) t
         left join lateral  (select   m
                             from     unnest(a) m
                             order by (m).post_time
                             limit    1) m on true
         where     (t).thread_type = 'c2s'
         order by  coalesce((m).thread_id, (t).thread_id), (t).post_time) t
order by t.ticket_id, t.c2s_time;
create or replace function first_agg_val(anyelement, anyelement)
  returns anyelement
  language sql
  immutable
  strict
  as 'select $1';

create aggregate first_agg(
  sfunc    = first_agg_val,
  basetype = anyelement,
  stype    = anyelement
);

select  t.*, row_number() over (partition by t.ticket_id order by t.c2s_time) rank
from    (select    distinct on (coalesce((s2c).thread_id, (c2s).thread_id))
                   (c2s).ticket_id,
                   (c2s).post_time c2s_time,
                   (c2s).message c2s_message,
                   (s2c).post_time s2c_time,
                   (s2c).message s2c_message,
                   (s2c).post_time - (c2s).post_time time_taken
         from      (select t c2s, first_agg(t) filter (where thread_type = 's2c')
                                                 over (partition by ticket_id
                                                       order by     post_time
                                                       rows between current row and unbounded following) s2c
                    from   ticket_thread t) t
         where     (c2s).thread_type = 'c2s'
         order by  coalesce((s2c).thread_id, (c2s).thread_id), (c2s).post_time) t
order by t.ticket_id, t.c2s_time;
如果您不需要排名,您可以摆脱它们存在的外部查询,纯粹是为了排名。这在客户端通常很容易计算

PS:MyQueries的time_take列是一个。如果您不喜欢/无法解析该列,则可以使用以下公式,以秒为单位获取时差:


主要使用窗口功能的替代解决方案:

select ticketid, c2stime, s2ctime, s2ctime- c2stime as timetaken, rank() over w
from (
    select ticketid, threadtype, posttime as c2stime, lead(posttime) over w as s2ctime
    from (
        select *, lag(threadtype) over w
        from ticket_thread
        where threadtype <> 's2s'
        window w as (partition by ticketid order by threadid)
        ) s
    where threadtype <> coalesce(lag, '')
    window w as (partition by ticketid order by threadid)
    ) s
where threadtype = 'c2s'
window w as (partition by ticketid order by c2stime)
order by ticketid, c2stime;

 ticketid | c2stime  | s2ctime  | timetaken | rank 
----------+----------+----------+-----------+------
       12 | 12:20:20 | 12:30:20 | 00:10:00  |    1
       12 | 12:40:00 | 12:55:30 | 00:15:30  |    2
       12 | 13:10:00 |          |           |    3
       13 | 12:20:20 |          |           |    1
(4 rows)

编辑问题并从表中添加示例数据以获得所需的输出。输出中的排名是多少?这只是一些基于订单的编号吗?又称作这是什么?@pozs是的,它的使用让我可以很容易地知道客户和支持成员之间来回回复的次数。shi@pozs,感谢您的及时回复。你的脚本几乎成功了,但是如果客户在员工回复之前发送了两个或更多帖子,例如:你的两个脚本都失败了。好吧,第二种方法几乎奏效了,如果没有显示额外的帖子信息,那么这正是我想要的。编辑:我加入这条消息只是为了用作评论。@Willy_Sunny,我明白了;那么您将需要稍微高级一些的查询。我更新了我的帖子,请查看。出于某种原因,当我试图在我的工作机器上使用该脚本时,它一直告诉我在filter语句处或附近有一个synax错误,不确定这是否是因为我在9.3上工作,而网站正在使用9.6=\@Willy\u Sunny是的,filter子句是一个9.4+功能。对于9.3,您可以使用模拟过滤器的第一个变体,这将需要更复杂的查询,如果我们有其他方法,这是不值得的。感谢您的脚本工作得很好,但我注意到一个错误,我已经修复了它,您的不存在过滤器应该在过滤器中包含一个ticket\u id=c2s.ticket\u id,或者,如果支持人员在回答第一个客户之前先回答第二个客户,则会导致错误版本:Fiixed版本:
create or replace function first_agg_val(anyelement, anyelement)
  returns anyelement
  language sql
  immutable
  strict
  as 'select $1';

create aggregate first_agg(
  sfunc    = first_agg_val,
  basetype = anyelement,
  stype    = anyelement
);

select  t.*, row_number() over (partition by t.ticket_id order by t.c2s_time) rank
from    (select    distinct on (coalesce((s2c).thread_id, (c2s).thread_id))
                   (c2s).ticket_id,
                   (c2s).post_time c2s_time,
                   (c2s).message c2s_message,
                   (s2c).post_time s2c_time,
                   (s2c).message s2c_message,
                   (s2c).post_time - (c2s).post_time time_taken
         from      (select t c2s, first_agg(t) filter (where thread_type = 's2c')
                                                 over (partition by ticket_id
                                                       order by     post_time
                                                       rows between current row and unbounded following) s2c
                    from   ticket_thread t) t
         where     (c2s).thread_type = 'c2s'
         order by  coalesce((s2c).thread_id, (c2s).thread_id), (c2s).post_time) t
order by t.ticket_id, t.c2s_time;
extract(epoch from <interval expresssion>)
select ticketid, c2stime, s2ctime, s2ctime- c2stime as timetaken, rank() over w
from (
    select ticketid, threadtype, posttime as c2stime, lead(posttime) over w as s2ctime
    from (
        select *, lag(threadtype) over w
        from ticket_thread
        where threadtype <> 's2s'
        window w as (partition by ticketid order by threadid)
        ) s
    where threadtype <> coalesce(lag, '')
    window w as (partition by ticketid order by threadid)
    ) s
where threadtype = 'c2s'
window w as (partition by ticketid order by c2stime)
order by ticketid, c2stime;

 ticketid | c2stime  | s2ctime  | timetaken | rank 
----------+----------+----------+-----------+------
       12 | 12:20:20 | 12:30:20 | 00:10:00  |    1
       12 | 12:40:00 | 12:55:30 | 00:15:30  |    2
       12 | 13:10:00 |          |           |    3
       13 | 12:20:20 |          |           |    1
(4 rows)