uma pergunta sobre o grupo SQL pela

votos
2

Eu tenho uma tabela chamada visitar parecida com esta:

id | visitor_id | visit_time 
-------------------------------------
 1 |          1 | 2009-01-06 08:45:02 
 2 |          1 | 2009-01-06 08:58:11
 3 |          1 | 2009-01-06 09:08:23 
 4 |          1 | 2009-01-06 21:55:23
 5 |          1 | 2009-01-06 22:03:35

Eu quero trabalhar um sql que pode obter quantas vezes um usuário visita dentro de uma sessão (intervalo sucessivo de visita menos de 1 hora).

Assim, para os dados de exemplo, eu quero começar seguinte resultado:

visitor_id | count
-------------------
         1 |     3
         1 |     2

BTW, eu uso o PostgreSQL 8.3. Obrigado!

ATUALIZAÇÃO : atualizado a data e hora na tabela de dados de exemplo. Desculpe pela confusão.
ATUALIZAÇÃO : Eu não me importo muito se a solução é uma única consulta SQL, utilizando o procedimento de armazenamento, etc. subconsulta Eu só me importo como obtê-lo feito :)

Publicado 06/01/2009 em 09:57
fonte usuário
Em outras línguas...                            


7 respostas

votos
0

Um ou ambos destes pode trabalhar? No entanto, ambos vão acabar dando-lhe mais colunas no resultado do que você está pedindo.

SELECT visitor_id,
       date_part('year', visit_time),
       date_part('month', visit_time),
       date_part('day', visit_time),
       date_part('hour', visit_time),
       COUNT(*)
  FROM visiting
 GROUP BY 1, 2, 3, 4, 5;


SELECT visitor_id,
       EXTRACT(EPOCH FROM visit_time)-(EXTRACT(EPOCH FROM visit_time) % 3600),
       COUNT(*)
  FROM visiting
 GROUP BY 1, 2;
Respondeu 06/01/2009 em 10:06
fonte usuário

votos
1

A questão é um pouco ambígua, porque você está fazendo a suposição ou exigindo que as horas vão começar em um ponto definido, ou seja, uma consulta natural também indicam que há um registro resultado de (1,2) para todas as visitas entre o horas de 08:58 e 09:58. Você teria que "dizer" a sua consulta que os horários de início são para algumas visitas razão determináveis ​​1 e 4, ou você deseja obter o conjunto de resultados natural:

visitor_id | count 
--------------------
         1 | 3
         1 | 2 <- extra result starting at visit 2
         1 | 1 <- extra result starting at visit 3
         1 | 2
         1 | 1 <- extra result starting at visit 5

Essa lógica extra vai ser caro e complicado demais para minha mente frágil, esta manhã, alguém melhor do que eu em postgres provavelmente pode resolver isso.

Eu normalmente querem resolver isso por ter uma coluna sessionKey na tabela que pude barata grupo, por razões perforamnce, mas há também um problema lógico que eu penso. Derivando informações de sessão de horários parece perigoso para mim, porque eu não acredito que o usuário será definitivamente desconectado após uma hora de atividade . A maioria sistemas sessão de trabalho por expirar a sessão após um período de inatividade , ou seja, é muito provável que uma visita depois de 9:45 vai ser na mesma sessão porque o seu período horário vai ser redefinidos a 09:08.

Respondeu 06/01/2009 em 10:07
fonte usuário

votos
0

Isso não pode ser feito em um único SQL. A melhor opção é segurá-lo no procedimento armazenado

Respondeu 06/01/2009 em 10:08
fonte usuário

votos
0

Se fosse T-SQL, gostaria de escrever algo como:

SELECT  visitor_id, COUNT(id), 
        DATEPART(yy, visit_time), DATEPART(m, visit_time), 
        DATEPART(d, visit_time), DATEPART(hh, visit_time)
FROM visiting
GROUP BY
    visitor_id, 
    DATEPART(yy, visit_time), DATEPART(m, visit_time), 
    DATEPART(d, visit_time), DATEPART(hh, visit_time)

o que me dá:

1   3   2009    1   6   8
1   2   2009    1   6   21

Eu não sei como ou se você pode escrever isso em postgre embora.

Respondeu 06/01/2009 em 10:24
fonte usuário

votos
1

O problema parece um pouco confuso.

Ele fica mais complicado como id 3 é dentro de uma hora de ID 1 e 2, mas se o usuário tinha visitado às 9:50, então, que teria sido dentro de uma hora de 2 mas não 1.

Você parece ser depois de um total alisou - para uma dada visita, quantas visitas estão dentro da hora seguinte?

Talvez você deve estar se perguntando por quantas visitas têm uma visita a menos de uma hora distante suceder? Se uma visita é menos de uma hora a partir do um precedente, em seguida, deve-o 'count'?

Então, o que você provavelmente quer é quantas cadeias que você tem, onde as ligações são menos de uma quantidade arbitrária (por isso o hipotético 09:50 visita seria incluída na cadeia que começa com id 1).

Respondeu 06/01/2009 em 11:07
fonte usuário

votos
1

há uma solução simples

Não há nenhuma maneira de fazer isso em um único statment SQL.
Abaixo estão 2 idéias: um usa um loop para contar visitas, o outro muda a forma como a visitingtabela é preenchida.

solução circuito

No entanto, isso pode ser feito sem muita dificuldade com um loop.
(Eu tentei obter a sintaxe PostgreSQL correta, mas eu não sou nenhum perito)

/* find entries where there is no previous entry for */ 
/* the same visitor within the previous hour:        */ 

select v1.* , 0 visits 
into temp_table
from visiting v1
where not exists ( select 1 
                   from   visiting v2
                   where  v2.visitor_id = v1.visitor_id 
                   and    v2.visit_time < v1.visit_time 
                   and    v1.visit_time - interval '1 hour' <     v2.visit_time 
                 )  
select @rows = @@rowcount 

while @rows > 0 
begin
    update temp_table
    set    visits = visits + 1 , 
           last_time = v.visit_time 
    from   temp_table t , 
           visiting   v 
    where  t.visitor_id = v.visitor_id 
    and    v.visit_time - interval '1 hour' < t.last_time
    and    not exists ( select 1 
                        from   visiting v2 
                        where  v2.visitor_id = t.visitor_id 
                        and    v2.visit_time between t.last_time and v.visit_time 
                      ) 

    select @rows = @@rowcount 
end

/* get the result: */ 

select visitor_id, 
       visits 
from temp_table 

A idéia aqui é fazer isso:

  • obter todas as visitas em que não há visita anterior dentro de uma hora.
    • este identifica as sessões
  • loop, recebendo a próxima visita para cada um desses "primeiras visitas"
    • até que não haja mais "próximas visitas"
  • Agora você pode apenas ler o número de visitas em cada sessão.

melhor solução?

Eu sugiro:

  • adicionar uma coluna à visitingtabela:session_id int not null
  • alterar o processo que faz com que as entradas para que ele verifica para ver se a visita anterior pelo visitante atual foi inferior a uma hora atrás. Se assim for, ele define session_id para o mesmo que o session id para que a visita anterior. Se não, ele gera um novo session_id .
  • você poderia colocar esta lógica em um gatilho.

Em seguida, sua consulta original pode ser resolvido por:

SELECT session_id, visitor_id, count(*)
FROM   visiting 
GROUP BY session_id, visitor_id

Espero que isto ajude. Se eu cometi erros (eu tenho certeza que eu tenho), deixe um comentário e eu vou corrigi-lo.

Respondeu 06/01/2009 em 13:05
fonte usuário

votos
1

PostgreSQL 8.4 terá uma função de janelas, então podemos eliminar a criação de tabela temporária apenas para simular rownumbers (fins de sequência)

create table visit
(
visitor_id int not null,
visit_time timestamp not null
);




insert into visit(visitor_id, visit_time) 
values
(1, '2009-01-06 08:45:02'),
(2, '2009-02-06 08:58:11'),
(1, '2009-01-06 08:58:11'),
(1, '2009-01-06 09:08:23'),
(1, '2009-01-06 21:55:23'),
(2, '2009-02-06 08:59:11'),
(2, '2009-02-07 00:01:00'),
(1, '2009-01-06 22:03:35');




create temp table temp_visit(visitor_id int not null, sequence serial not null, visit_time timestamp not null);
insert into temp_visit(visitor_id, visit_time) select visitor_id, visit_time from visit order by visitor_id, visit_time;


select 
    reference.visitor_id, count(nullif(reference.visit_time - prev.visit_time < interval '1 hour',false))
from temp_visit reference
left join temp_visit prev 
on prev.visitor_id = reference.visitor_id and prev.sequence = reference.sequence - 1
group by reference.visitor_id;
Respondeu 06/01/2009 em 14:27
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more