#postgresql
Вопрос:
Я хотел бы присоединиться к следующим двум таблицам
Пользователи:
идентификатор пользователя | имя пользователя |
---|---|
12 | Джон |
13 | Брайан |
14 | Стив |
15 | Барри |
посещения:
идентификатор пользователя | посещение_страницы |
---|---|
пользователь_12 | gasvhs |
пользователь_12,пользователь_14 | dfvjk |
пользователь_15 | djvnjv |
пользователь_14,пользователь_15 | sdhjcb |
ОЖИДАЕМЫЕ РЕЗУЛЬТАТЫ:
посещение_страницы | имя пользователя |
---|---|
gasvhs | Джон |
dfvjk | Джон;Стив |
djvnjv | Барри |
sdhjcb | Стив;Барри |
Используя следующий запрос, я получаю результат, показанный ниже
Запрос, который я написал:
SELECT visited_page, user_name
FROM VISITS
JOIN
USERS on substring(user_id::VARCHAR FROM '[0-9] ')::INT = users.user_id
РЕЗУЛЬТАТЫ, КОТОРЫЕ Я ПОЛУЧИЛ:
посещение_страницы | имя пользователя |
---|---|
gasvhs | Джон |
dfvjk | Джон |
djvnjv | Барри |
sdhjcb | Стив |
Есть какие-нибудь предложения о том, как получить ожидаемые результаты ?
Комментарии:
1. Пожалуйста, не размещайте здесь ссылки на фотографии. И, пожалуйста, также не включайте фотографии напрямую. Здесь, на SO, рекомендуется публиковать все ваши данные в виде текста (обычно в блоках кода с использованием тройных обратных ссылок). Пожалуйста, переработайте свой вопрос, спасибо.
2. Что с этим
substring(user_id::VARCHAR FROM '[0-9] ')::INT
такое ? Почему этоvisits.user_id
не целочисленный столбец?3. На самом деле не совсем ясно, как вы приходите к этому ожидаемому результату. У вас есть четыре пользователя, и ровно по одному посещению каждым из них в ваших данных примера.
4. Привет @Berhi — Это визит.идентификатор пользователя-это ТЕКСТ.
5. Извините, ребята. В приведенных мной образцах данных были некоторые проблемы, и я просто исправил их
Ответ №1:
Это отличный пример того, почему хранение списка, разделенного запятыми, — такая очень, очень плохая идея.Это уже достаточно плохо, зачем вам когда-либо добавлять к идентификатору пользователя текстовую строку? :(. Первое, что нужно сделать, это развернуть visits.user_id в отдельные строки, а затем удалить префикс. В результате получается то, какой visits
должна была быть таблица в первую очередь (за вычетом обязательного FK, конечно).
select (replace(user_id,'user_',''))::integer user_id,visited_page
from ( select unnest(string_to_array(user_id, ',')) user_id, visited_page
from visits
) s;
Имея это на месте, мы можем ПРИСОЕДИНИТЬ его к пользователям и агрегировать имя пользователя по странице; Давая окончательный запрос: (см. демонстрацию)
select v.visited_page
, string_agg( u.user_name, ',' order by u.user_name) users_visiting
from users u
join( select (replace(user_id,'user_',''))::integer user_id,visited_page
from ( select unnest(string_to_array(user_id, ',')) user_id, visited_page
from visits
) s
) v
on (v.user_id = u.user_id)
group by v.visited_page
order by v.visited_page;
Предложение: Нормализуйте таблицы и не сохраняйте списки. Это приведет к упрощению запросов, повышению производительности и обеспечению целостности данных. Рассмотрим, что произойдет с текущей схемой, если бы идентификатор пользователя был просто перенесен (потенциально чрезвычайно распространенная ошибка) как 41 вместо 14, а пользователь 41 не существовал. И не создавайте ненужных префиксов к значениям данных, чтобы сообщить вам, что это такое, имя уже делает это — по крайней мере, если вы выбираете хорошие имена и непротиворечивы. Но это темы для другого дня.