2017-02-22 61 views
0

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

My code is : 

select tb1.*, tb2.* from 
(select username, via_mobile as pc, max(review_date) as pcdate from tripadvisor where username != "" and via_mobile='false' group by username) tb1 
join 
(select username, via_mobile as mobile, max(review_date) as mobile from tripadvisor whereusername != "" and via_mobile='true' group by username) tb2 
on tb1.username = tb2.username; 

Проблема в том, я не может получить правильный обзор на нужную дату. Например:

username; review_date; title 
Alan; 2012-12-18 ;"If..." 

Но он должен показать Alan; 2012-12-18; "Nice hotel"

Можете ли вы помочь мне исправить код.

+0

См http://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve-for-what -seems-to-me-to-be-a-very-simple-sql-query – Strawberry

+0

«Nice Hôtel» ... смешно – Strawberry

ответ

1

Ваш вопрос немного неясен, но если я правильно понимаю, вы ищете каждую полную строку с наивысшей датой, выбранную четко/сгруппированную по имени пользователя? Это должно дать вам, что:

SELECT 
    username, 
    review_date, 
    title 
FROM 
    tripadvisor AS ta 
    INNER JOIN (
    SELECT 
     username, 
     max(review_date) AS review_date 
    FROM 
     tripadvisor 
    GROUP BY 
     username 
) AS max_table 
    ON ta.username = max_table.username 
     AND ta.review_date = max_table.review_date; 
WHERE 
    username != '' 
    -- any extra where clauses go here 

См: How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?

+1

Если есть две или несколько строк с тем же самым самым последним 'review_date' для данного' username ', этот запрос вернет две или несколько строк для этого имени пользователя. Это, вероятно, краевой случай. Вероятно, мы ожидаем, что '(username, review_date)' будет уникальным. Но мы не видим никакой гарантии этого. Кроме того, исходный запрос, по-видимому, ограничивает строки теми, у которых есть via_mobile = 'true' или via_mobile = 'false', исключая, например, rows with via_mobile = 'unknown'. Но эти две незначительные проблемы в стороне, этот запрос демонстрирует нормативный подход к возврату «последней строки».+10 – spencer7593

+1

Правда, хотя, если честно, я был очень неясен в отношении дифференциации pc/mobile, и это казалось плохим нормализацией; если OP не пытается получить самую последнюю дату для мобильных устройств и самую последнюю дату для ПК в той же строке ... Я просто написал запрос, настроенный на таблицу результатов OP, но ваш ответ более приспособлен к тому, как OP писали свои запрос. +1 –

+1

Да, спецификация неточна; существует несколько способов интерпретировать его, относительно того, какие строки должны быть возвращены при каких обстоятельствах. Цель моего комментария состояла в том, чтобы указать на некоторые конкретные случаи. Я не собирался критиковать запрос в этом ответе. Этот запрос является хорошей демонстрацией и намного чище, чем запрос в моем ответе. Я бы +10 снова, если бы это разрешило мне. – spencer7593

1

Если цель состоит в том, чтобы вернуть самый последний титул для обзора «мобильный» и «ПК», я бы что-то вроде этого:

SELECT q.username 
    , MAX(q.pc_date)  AS pc_date 
    , MAX(p.title)  AS pc_title 
    , MAX(q.mobile_date) AS mobile_date 
    , MAX(r.title)  AS mobile_title 
    FROM (SELECT t.username 
       , MAX(IF(t.via_mobile='false',t.review_date,NULL) AS pc_date 
       , MAX(IF(t.via_mobile='true',t.review_date,NULL) AS mobile_date 
      FROM tripadvisor t 
      WHERE t.username <> '' 
      AND t.via_mobile IN ('true','false') 
      GROUP 
      BY t.username 
     ) q 
    LEFT 
    JOIN tripadvisor p 
    ON p.username = q.username 
    AND p.review_date = q.pc_date 
    AND p.via_mobile = 'false' 
    LEFT 
    JOIN tripadvisor r 
    ON r.username = q.username 
    AND r.review_date = q.mobile_date 
    AND r.via_mobile = 'true' 
GROUP 
    BY q.username 

Если у пользователя есть только «мобильные» обзоры и нет отзывов «pc», этот запрос вернет строку, но с значениями NULL для столбцов «pc». Аналогично, запрос возвращает значения NULL для «мобильных» столбцов для пользователя, имеющего только «pc» отзывы.

Запрос может быть легко изменен только для того, чтобы возвращать строки для пользователей, которые имеют как «мобильные», так и «ПК» отзывы, чтобы быть ближе к оригиналу, используя INNER JOIN.


Если цель проще, просто возвращал только самый последний обзор ...

SELECT r.username 
    , r.review_date 
    , MAX(r.title)  AS title 
    , MAX(r.via_mobile) AS via_mobile 
    FROM (SELECT t.username 
       , MAX(t.review_date) AS max_review_date 
      FROM tripadvisor t 
      WHERE t.username <> '' 
      AND t.via_mobile IN ('true','false') 
      GROUP 
      BY t.username 
     ) q 
    JOIN tripadvisor r 
    ON r.username = q.username 
    AND r.review_date = q.max_review_date 
    AND r.via_mobile IN ('true','false') 
GROUP 
    BY r.username 
    , r.review_date 

Результаты этого запроса несколько неопределенные, когда username имеет несколько строк с одинаковым (последним) review_date. Это гарантирует, что одна строка будет возвращена, но title и via_mobile могут быть не из одной строки.

0

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

Существование испытывается EXISTS в коррелировала подзапрос:

SELECT * FROM tripadvisor as T 
where exists ( 
    select 1 from tripadvisor 
    where username = T.username 
    group by username 
    having MAX(review_date) = T.review_date 
);