I have multiple logouts for many users. I want to get the last logout for every user for every day.
SELECT t_logouts.log_id,
t_users.last_name || ' ' || t_users.first_name,
t_logouts.log_date,
MAX(t_logouts.log_time),
(DATE_PART('hour', '18:00:00'::time - t_logouts.log_time ) * 60 +
DATE_PART('minute', '18:00:00'::time - t_logouts.log_time )) / 60
FROM t_logouts
LEFT JOIN t_users
ON t_users.user_id = t_logouts.user_id
GROUP BY DATE(t_logouts.log_date), t_users.user_id
ORDER BY t_logouts.log_date DESC, t_logouts.log_time ASC ;
Throws error:
LINE 1: SELECT t_logouts.log_id,
^
SQL state: 42803
Character: 8
There are some problem with multiple aggregation as far as I understand. I've tried to use this manual: https://www.postgresqltutorial.com/postgresql-group-by/ https://www.postgresqltutorial.com/postgresql-max-function/
Tables I am trying to work with.
CREATE TABLE t_users (
user_id SERIAL PRIMARY KEY,
nickname name UNIQUE not null check (length(nickname) < 64),
first_name VARCHAR NOT NULL check (length(first_name) < 64),
last_name VARCHAR NOT NULL check (length(last_name) < 64),
email VARCHAR DEFAULT NULL check (email ~* '^.+@.+\..+$' )
);
CREATE TABLE t_logins (
log_id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
FOREIGN KEY (user_id)
REFERENCES t_users (user_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
log_date DATE NOT NULL,
log_time TIME NOT NULL
);
CREATE TABLE t_logouts (
log_id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
FOREIGN KEY (user_id)
REFERENCES t_users (user_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
log_date DATE NOT NULL,
log_time TIME NOT NULL
);
This is typically done using distinct on ()
in Postgres:
SELECT distinct on (t_users.user_id)
t_logouts.log_id,
t_users.last_name || ' ' || t_users.first_name,
t_logouts.log_date,
t_logouts.log_time,
extract(epoch from '18:00:00'::time - t_logouts.log_time) / 3600
FROM t_logouts
LEFT JOIN t_users ON t_users.user_id = t_logouts.user_id
ORDER BY t_users.user_id, t_logouts.log_date DESC;