Как сделать заказ на отфильтрованный имеет много отношения - PullRequest
0 голосов
/ 29 июня 2018

У меня есть users locations и таблица соединений visits. Каждый пользователь может посетить несколько мест, и я хочу просмотреть пользователей, упорядоченных по названию места их последнего посещения.

CREATE TABLE users
  ("id" int, "name" varchar(128))
;

CREATE TABLE locations
  ("id" int, "name" varchar(128))
;

CREATE TABLE visits
  ("id" int, "user_id" int, "location_id" int, "date" timestamp)
;

INSERT INTO users
    ("id", "name")
VALUES
    (1, 'Alpha'),
    (2, 'Bravo'),
    (3, 'Charlie');

INSERT INTO locations
    ("id", "name")
VALUES
    (4, 'Delta'),
    (5, 'Echo'),
    (6, 'Foxtrott');

INSERT INTO visits
  ("id", "user_id", "location_id", "date")
VALUES
  (1, 1, 4, '2000-02-03 00:00:00'),
  (2, 1, 5, '2000-02-02 00:00:00'),
  (3, 1, 6, '2000-02-01 00:00:00'),
  (4, 2, 6, '2000-01-01 00:00:00'),
  (5, 2, 5, '2000-01-01 00:00:00')
;

Я пытался

SELECT users.id, users.name, max(locations.name) as location_name, max(visits.date) as date
FROM users
LEFT JOIN visits ON users.id = visits.user_id
LEFT JOIN locations ON visits.location_id = locations.id
GROUP BY users.id, users.name
ORDER BY location_name

, но max (location.name) не зависит от max (посещения.даты)

еще одна попытка

SELECT users.id, users.name, t.date, locations.name as location_name
FROM users
LEFT JOIN (
  SELECT MAX(date) as date, user_id
  FROM visits
  GROUP BY user_id
) AS t ON users.id = t.user_id
LEFT JOIN visits on visits.date = t.date
LEFT JOIN locations on locations.id = visits.location_id
ORDER BY location_name

но возникают проблемы, когда у одного пользователя два посещения в одну и ту же дату (мне все равно, какое место выбирают, но оно должно быть только одно)

результат должен выглядеть примерно так, хотя дата не требуется.

id  name     date                  location_name
1   Alpha    2000-02-03T00:00:00Z  Delta
2   Bravo    2000-01-01T00:00:00Z  Echo
3   Charlie  (null)                (null)

решение предпочтительно в ActiveRecord, но обычный sql тоже подойдет

http://sqlfiddle.com/#!17/ba2a6/1

Ответы [ 3 ]

0 голосов
/ 29 июня 2018

Ниже запрос даст желаемый результат.

Я заполнил ваши образцы данных в CTE.

Также нет необходимости группировать и агрегировать функции, такие как макс. Здесь не требуется.

      with users(id,name) as (
      select *
      from (
        values
        (1, 'Alpha'),
        (2, 'Bravo'),
        (3, 'Charlie')
      ) t
    ), locations(id,name) as (
      select *
      from(
        values
        (4, 'Delta'),
        (5, 'Echo'),
        (6, 'Foxtrott')
      ) t
    ), visits(id,user_id,location_id,date) as (
      select *
      from(
      VALUES
      (1, 1, 4, '2000-02-03 00:00:00'),
      (2, 1, 5, '2000-02-02 00:00:00'),
      (3, 1, 6, '2000-02-01 00:00:00'),
      (4, 2, 6, '2000-01-01 00:00:00'),
      (5, 2, 5, '2000-01-01 00:00:00')
      ) t
    ), res as (
    select
      distinct on(user_id)
      u.id as user_id,
      u.name,
      l.name as location_name,
      date
    from visits v
    join locations l on l.id=location_id
    right join users u on u.id=v.user_id
    order by user_id,date desc
   )
   select * from res order by location_name
0 голосов
/ 29 июня 2018

Отличная работа @Sabari:

Я только что написал похожий запрос и пришел сюда, чтобы увидеть, что вы уже опубликовали его. Это в основном тот же запрос, который использует только LEFT JOIN. Я все равно держу это.

SELECT DISTINCT ON (user_id) u.id
    ,u.name
    ,l.name
    ,DATE
FROM users u 
LEFT JOIN visits v ON u.id = v.user_id 
LEFT JOIN locations l ON l.id = location_id
ORDER BY user_id
    ,DATE DESC

Демонстрация Fiddle

0 голосов
/ 29 июня 2018

Небольшая коррекция по группировкам:

SELECT users.id, users.name, max(locations.name) as location_name, visits.date as date
FROM users
LEFT JOIN visits ON users.id = visits.user_id
LEFT JOIN locations ON visits.location_id = locations.id
where visits.date = (select max(date) from visits where user_id = users.id)
GROUP BY users.id, users.name,visits.date
ORDER BY location_name

Здесь вы можете подтвердить, что он дает правильные результаты: http://sqlfiddle.com/#!17/24a0d/27

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...