2010-10-06 1 views
2

Эй, все. Я считаю, что это вопрос «большой-на-группу», но даже после рассмотрения нескольких вопросов о StackOverflow я не уверен, как применить это к моей ситуации ...Ошибка MySQL наибольшая-на-группу

Я использую базу данных MySQL и есть система основного блог типа создать о компьютерных приложениях ... Таблица выглядеть следующим образом:

POSTS 
post_id 
post_created 
post_type  -- could be article, review, feature, whatever 
post_status -- 'a' approved or 'd' for draft 

APPS 
app_id 
app_name 
app_platform -- Windows, linux, unix, etc.. 

APP_TO_POST -- links my posts to its relevant application 
atp_id 
atp_app_id 
atp_post_id 

Я использую следующий основной запрос, чтобы вывести все статьи для приложения с названием «Photoshop» где тип сообщения является «статьей», а статус статьи «a» для одобренных:

SELECT apps.app_name, apps.app_platform, posts.post_created, posts.post_id 
FROM apps 
JOIN app_to_post ON app_to_post.atp_app_id = apps.app_id 
JOIN posts ON app_to_post.atp_post_id = posts.post_id 
WHERE apps.app_name = 'Photoshop' 
AND 
posts.post_type = 'Article' 
AND 
posts.post_status = 'a' 

Что заставляет меня эти ожидаемые результаты:

app_name app_platform post_created  post_id 
Photoshop Windows  Oct. 20th, 2009 1 
Photoshop Windows  Dec. 1, 2009  3 
Photoshop Macintosh  Nov. 10th, 2009 2 

ли кто-нибудь быть в состоянии протянуть руку, как я мог бы изменить этот запрос к только тянуть самую последнюю статью за прикладную платформу? Так, например, я бы хотел, чтобы мои результаты выглядеть следующим образом:

app_name app_platform post_created  post_id 
Photoshop Windows  Dec. 1, 2009  3 
Photoshop Macintosh  Nov. 10th, 2009 2 

И опустить одну из 'Photoshop Windows' статей, потому что это не самая последняя.

Если я просто наклеил на MAX(post_created) и GROUP BY app_platform мои результаты не всегда группируются правильно. Насколько я понимаю, мне нужно выполнить какое-то внутреннее соединение суб-запроса?

ответ

0

Вы на правильном пути.

Попробуйте добавить

group by app_name,app_platform 
having post_created=max(post_created) 

Или, если ваш post_id последователен, где большее значение всегда будет отражать более поздний пост, используйте этот имеющий пункт: having post_id=max(post_id)

+1

Я работаю с аналогичной проблемой, и оператор «having» не решает проблему. Кажется, что MySQL сообщает первый результат, который он находит для каждой сгруппированной строки, и все «имеющие» будут полностью исключать любые строки, для которых первый результат не соответствует максимальному результату. –

4

Поскольку у вас есть много JOIN с, я предлагаю создавая VIEW первый:

CREATE VIEW articles AS 
    SELECT a.app_name, a.app_platform, p.post_created, p.post_id 
    FROM  apps a 
    JOIN  app_to_post ap ON ap.atp_app_id = a.app_id 
    JOIN  posts p ON ap.atp_post_id = p.post_id 
    WHERE  p.post_type = 'Article' AND p.post_status = 'a'; 

Затем вы можете использовать NULL-автообъединение:

SELECT  a1.app_name, a1.app_platform, a1.post_created, a1.post_id 
FROM  articles a1 
LEFT JOIN articles a2 ON 
      a2.app_platform = a1.app_platform AND a2.post_created > a1.post_created 
WHERE  a2.post_id IS NULL; 

Тестовый пример:

CREATE TABLE posts (
    post_id   int, 
    post_created  datetime, 
    post_type  varchar(30), 
    post_status  char(1) 
); 

CREATE TABLE apps (
    app_id   int, 
    app_name   varchar(40), 
    app_platform  varchar(40) 
); 

CREATE TABLE app_to_post (
    atp_id   int, 
    atp_app_id  int, 
    atp_post_id  int 
); 

INSERT INTO posts VALUES (1, '2010-10-06 05:00:00', 'Article', 'a'); 
INSERT INTO posts VALUES (2, '2010-10-06 06:00:00', 'Article', 'a'); 
INSERT INTO posts VALUES (3, '2010-10-06 07:00:00', 'Article', 'a'); 
INSERT INTO posts VALUES (4, '2010-10-06 08:00:00', 'Article', 'a'); 
INSERT INTO posts VALUES (5, '2010-10-06 09:00:00', 'Article', 'a'); 

INSERT INTO apps VALUES (1, 'Photoshop', 'Windows'); 
INSERT INTO apps VALUES (2, 'Photoshop', 'Macintosh'); 

INSERT INTO app_to_post VALUES (1, 1, 1); 
INSERT INTO app_to_post VALUES (1, 1, 2); 
INSERT INTO app_to_post VALUES (1, 2, 3); 
INSERT INTO app_to_post VALUES (1, 2, 4); 
INSERT INTO app_to_post VALUES (1, 1, 5); 

Результат:

+-----------+--------------+---------------------+---------+ 
| app_name | app_platform | post_created  | post_id | 
+-----------+--------------+---------------------+---------+ 
| Photoshop | Macintosh | 2010-10-06 08:00:00 |  4 | 
| Photoshop | Windows  | 2010-10-06 09:00:00 |  5 | 
+-----------+--------------+---------------------+---------+ 
2 rows in set (0.00 sec) 

В качестве побочного сведению, в общем, вы не нуждаетесь в surrogate key для вашего junction table.Вы могли бы также создать составной первичный ключ (и в идеале внешние ключи упомянутых таблиц):

CREATE TABLE app_to_post (
    atp_app_id  int, 
    atp_post_id  int, 
    PRIMARY KEY (atp_app_id, atp_post_id), 
    FOREIGN KEY (atp_app_id) REFERENCES apps (app_id), 
    FOREIGN KEY (atp_post_id) REFERENCES posts (post_id) 
) ENGINE=INNODB; 
+0

Это нулевое соединение помогло решить подобную проблему для меня. –

+1

Это эффективный запрос? Вы присоединяетесь ко всем статьям, а затем присоединяетесь ко всему с самим собой. Мне это кажется дорогим. – marc40000

2

Давайте сначала рассмотрим, как получить строки с максимальным значением из вашего результата запроса и ваш желаемый результат:

Ваш результат: (Давайте назовем это таблица T)

app_name app_platform post_created  post_id 
Photoshop Windows  Oct. 20th, 2009 1 
Photoshop Windows  Dec. 1, 2009  3 
Photoshop Macintosh  Nov. 10th, 2009 2 

результат вы хотите:

app_name app_platform post_created  post_id 
Photoshop Windows  Dec. 1, 2009  3 
Photoshop Macintosh  Nov. 10th, 2009 2 

Для того, чтобы получить результат, вы должны:

  1. Вычислить максимальную post_id для каждой платформы для таблицы T.
  2. Регистрации максимального результата с исходной таблицей T, чтобы получить значение в других столбцах строки.

Запрос ниже:

SELECT 
    t1.app_name,t1.app_platform,t1.post_created,t1.post_id 
FROM 
    (SELECT app_platform, MAX(post_created) As MaxPostCreated 
    FROM T 
    GROUP BY app_platform) AS t2 JOIN 
    T AS t1 
WHERE 
    t1.app_platform = t2.app_platform1 
    AND t2.MaxPostCreated = t1.post_created 

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

Конечный результат объединения с частичным ответом является показать ниже (с видом):

CREATE VIEW T 
    SELECT a.app_name, a.app_platform, p.post_created, p.post_id 
    FROM  apps a 
    JOIN  app_to_post ap ON ap.atp_app_id = a.app_id 
    JOIN  posts p ON ap.atp_post_id = p.post_id 
    WHERE  p.post_type = 'Article' AND p.post_status = 'a'; 

SELECT 
    t1.app_name,t1.app_platform,t1.post_created,t1.post_id 
FROM 
    (SELECT app_platform, MAX(post_created) As MaxPostCreated 
    FROM T 
    GROUP BY app_platform) AS t2 JOIN 
    T AS t1 
WHERE 
    t1.app_platform = t2.app_platform1 
    AND t2.MaxPostCreated= t1.post_created 

Кстати, наша команда на самом деле в настоящее время разрабатывает инструмент пытается автоматически помочь пользователям писать запросы, и пользователи могут предоставить примеры ввода-вывода для инструмента, и инструмент будет обрабатывать запрос. (Первая часть запроса на самом деле сгенерирована инструментом! Ссылка на наш прототип: https://github.com/Mestway/Scythe)

Надеюсь, это может вам помочь. :)

 Смежные вопросы

  • Нет связанных вопросов^_^