2
votes

Postgres, obtenez des enregistrements uniques par jour à partir de la plage de dates sélectionnée

J'ai besoin de faire un rapport avec les utilisateurs connectés par plage de dates mais sans doublons le même jour (si quelqu'un a été connecté deux fois le même jour, nous ne le listerons pas deux fois). malheureusement, nous conservons les informations de connexion en tant que json (ouais, je ne peux pas les changer en table séparée, je ne sais pas qui a conçu cette base de données). Requête pour voir tous les utilisateurs connectés:

 id  |        username  |              email       |         login_date
-----+-------------------------+---------------------------------+----------------------------
 102 | example          | example@example.com      | 2018-12-06 09:30:10.573+00
  42 | rafal            | rafal@example.com        | 2018-12-06 09:45:24.884+00
 576 | john             | john@example.com         | 2018-12-06 09:35:24.922+00
 576 | john             | john@example.com         | 2018-12-07 09:58:04.253+00

Modifié est l'horodatage avec le fuseau horaire et il est utilisé comme date de connexion.

Je n'ai trouvé que des exemples avec le nombre d'identifiants distincts par jour mais Je ne sais pas comment le modifier pour obtenir des résultats distincts par jour

exemple de données:

 id  |        username  |              email       |         login_date
-----+-------------------------+---------------------------------+----------------------------
 102 | example          | example@example.com      | 2018-12-06 09:30:10.573+00
 102 | example          | example@example.com      | 2018-12-06 09:32:34.235+00
  42 | rafal            | rafal@example.com        | 2018-12-06 09:45:24.884+00
 576 | john             | john@example.com         | 2018-12-06 09:35:24.922+00
 576 | john             | john@example.com         | 2018-12-07 09:58:04.253+00

données recherchées:

select a.id, username, email, ah.modified as login_date
from accounts a join
     account_history ah
     on modified_acc_id = a.id
 where ah.data::jsonb->>'message' = 'Logon';

Comme vous pouvez le voir, sans deuxième ligne


1 commentaires

@GordonLinoff modifié


4 Réponses :


0
votes

Vous semblez vouloir le nombre de jours-utilisateur pour une période donnée. Si je comprends bien:

select count(*) as num_user_days_in_range
from (select a.username, date_trunc('day', ah.modified) as login_date
      from accounts a join
           account_history ah
           on modified_acc_id = a.id
      where ah.data::jsonb->>'message' = 'Logon'
      group by a.username, login_date
     ) u
where login_date >= $date1 and login_date < $date2


1 commentaires

J'ai édité ma question, je ne veux pas du nombre d'utilisateurs, juste des utilisateurs distincts par jour



0
votes

utiliser la fonction de fenêtre row_number()

select id,username,email,login_date from 
(
 select a.id, username, email, ah.modified as login_date,
row_number() over(partition by a.id, username,email order by ah.modified) rn
 from accounts a join
 account_history ah
 on modified_acc_id = a.id
 where ah.data::jsonb->>'message' = 'Logon'
) t where t.rn=1


0 commentaires

4
votes

DISTINCT ON vous donne exactement la première ligne d'un groupe ordonné. Dans votre exemple, le groupe est la partie id et la date de l’horodatage login_date

SELECT DISTINCT ON (a.id, ah.modified::date) 
    a.id, 
    username, 
    email, 
    ah.modified as login_date
FROM accounts a 
JOIN account_history ah
    ON modified_acc_id = a.id
WHERE ah.data::jsonb->>'message' = 'Logon'
ORDER BY a.id, ah.modified::date, ah.modified 

démo: db violon

Explication de ORDER Clause BY :

Vous devez d'abord classer par les colonnes DISTINCT . Mais dans votre cas, vous ne voulez pas vraiment commander par date uniquement, mais aussi par heure. Ainsi, après avoir trié par date (ce qui est nécessaire en raison de vos colonnes DISTINCT ), vous devez également classer par horodatage.


Ainsi, toute la requête pourrait être simplifiée en ( sans sous-requête):

SELECT DISTINCT ON (id, login_date::date)
    *
FROM (
    -- <your query>
) s
ORDER BY id, login_date::date, login_date


0 commentaires

0
votes

Il semble que quand il y a une dupe, vous prenez la date la plus tôt. Si tel est le cas, cela fonctionne-t-il?

select
  a.id, username, email, min (ah.modified) as login_date
from accounts a join
     account_history ah
     on modified_acc_id = a.id
 where ah.data::jsonb->>'message' = 'Logon'
group by a.id, username, email, ah.modified::date


0 commentaires