2011-11-28 12 views
8

Mam dwa stoły i staram się znaleźć "post" z najwyższym wynikiem na dzień.Grupa MySQL przez i max zwraca nieprawidłowe wiersze

CREATE TABLE IF NOT EXISTS `posts_points` (
    `post_id` int(10) unsigned NOT NULL, 
    `comments` smallint(5) unsigned NOT NULL, 
    `likes` smallint(5) unsigned NOT NULL, 
    `favorites` smallint(5) unsigned NOT NULL, 
    PRIMARY KEY (`post_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 


CREATE TABLE IF NOT EXISTS `posts` (
    `profile_id` int(10) unsigned NOT NULL, 
    `post_id` int(10) unsigned NOT NULL, 
    `pubdate_utc` datetime NOT NULL, 
    PRIMARY KEY (`post_id`), 
    KEY `profile_id` (`profile_id`), 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC; 

Próbowałem zapytanie poniżej. Zwraca prawidłowy wynik, ale pozostałe kolumny są po prostu losowymi wierszami. Co ja robię źle ?

SELECT p.post_id, p.profile_id 
    , MAX(t1.score) 
    , DATE_FORMAT(t1.pubdate_utc, '%d %b') post_date 
    , DATE(t1.pubdate_utc) mydate 
FROM 
(
    SELECT p.profile_id, p.post_id, p.pubdate_utc 
     , (pp.comments + pp.likes + pp.favorites) AS score 
    FROM posts p 
    INNER JOIN posts_points pp ON p.post_id = pp.post_id 
) t1 
INNER JOIN posts p ON t1.post_id = p.post_id 
    AND t1.pubdate_utc = p.pubdate_utc 
GROUP BY mydate 
ORDER BY mydate DESC 
LIMIT 18; 
+2

+1 za tym definicji tabeli – ManseUK

+0

nie robisz nic złego.Funkcje agregujące nie mają wpływu na wartość innych kolumn. Wydają się być "losowe". –

+0

Grupowanie według daty powinno generować dziwne zachowanie. – Alfabravo

Odpowiedz

0
Column1 Column2 
C  d 
A  any thing 
D  y 
B  z 

Jeśli tak to dane przez Kolumnie1 wtedy wygląda to tak ..... orderby prostu zamawia pierwszą kolumnę ....

Column1 Column2 
A  any thing 
B  z    
C  d 
D  y 
0

jest trochę trudne do zrozumienia co chcesz robić.

Słowa (kolumny (posty, komentarze, ulubione) i PK), zrozumiałem, że aktualizujesz wartości zwiększające się i nie zapisujesz każdego głosu.

to zaznaczenie Zwraca dane z postu, a wynik zamawiając większy punkt, ograniczone do 18

 SELECT P.post_id, 
       P.profile_id, 
       (PP.comments + PP.likes + PP.favorites) AS score, 
       DATE_FORMAT (P.pubdate_utc, '%d %b') AS post_data, 
       DATE (P.pubdate_utc) AS mydate 
      FROM posts P 
    INNER JOIN posts_points PP 
      ON (= P.post_id PP.post_id) 
     ORDER BY 3 DESC 
     LIMIT 18; 

Jeśli chcesz wybrać najwięcej głosów w ciągu dnia, należy rejestrować różne typy/favs, wymagają danych w tej tabeli (posts_points).

+0

'posts_points' jest tabelą podsumowującą, którą przygotowałem do debugowania i przyspieszenia. Każdy komentarz, podobnie jak i ulubiony, jest rejestrowany oddzielnie. Wygląda na to, że Twoje zapytanie znajdzie posty o najwyższym wyniku. Próbuję znaleźć wpis z najwyższym wynikiem dziennie w ciągu ostatnich 18 dni. Nie wiem, czy to ma sens. – user1070125

+0

Witaj, jaka jest jego struktura? Gdzie rekord komentarze/favs/lubi? Jeśli to konieczne, możesz zmienić tabele? – Cristian

0

Wow! Zdradliwy. Na przykład zawsze istnieje możliwość wiązania dla max.

Poniższe rozwiązanie tworzy pośrednią listę maks. Wyników dnia, a następnie pobiera wszystkie posty, których wyniki są równe maksimum z danego dnia. Zwraca więzy, więc możesz otrzymać dwa wiersze na dany dzień. Błagam o twoje wybaczenie, że nie mogę tego przetestować, więc podziel się z nami swoją opinią i jestem pewien, że możemy to zrobić, abyś zrobił to, czego potrzebujesz.

SELECT p.profile_id, p.post_id, p.pubdate_utc 
, DATE_FORMAT(p.pubdate_utc, '%d %b') AS post_date 
, DATE(p.pubdate_utc) AS mydate 
, (pp.comments + pp.likes + pp.favorites) AS score 
FROM posts p 
INNER JOIN posts_points pp ON p.post_id = pp.post_id 
INNER JOIN 
(
    SELECT p.pubdate_utc AS max_date, 
    (pp.comments + pp.likes + pp.favorites) AS max_score 
    FROM posts p2 
    INNER JOIN posts_points pp2 ON p2.post_id = pp2.post_id 
) m ON score = m.max_score 
AND mydate = m.max_date 
ORDER BY mydate DESC 
LIMIT 18; 
0

widać to zapytanie .Inner zapytania najpierw pobrać te rzędy, które mają taką samą POST_ID zarówno w tabeli niż suma (pp.comments + pp.likes + pp.favorites) jako wynik .Outer zapytanie jest pobranie maksymalnej oceniam i robię grupę na dzień mądry ...

SELECT post_id, profile_id 
    , MAX(score) 
    , DATE_FORMAT(pubdate_utc, '%d %b') post_date 
    , DATE(pubdate_utc) as mydate 
FROM 
(
    SELECT p.profile_id, p.post_id, p.pubdate_utc 
     , (pp.comments + pp.likes + pp.favorites) AS score 
    FROM posts p 
    INNER JOIN posts_points pp ON p.post_id = pp.post_id 
) 
GROUP BY pubdate_utc 
ORDER BY pubdate_utc DESC 
2

Wpadam w ten problem przez cały czas. Kiedy MySQL uruchamia funkcję agregującą, dla dowolnych niezagregowanych kolumn, po prostu ściąga pierwsze dane, przez które przechodzi, dla tej grupy, niezależnie od tego, czy pochodzi z wiersza MAX, czy nie. Musisz więc uporządkować dane w wewnętrznej kwerendzie tak, aby maksima były pierwsze w swoich grupach. Sprawdź, czy to działa:

SELECT t.post_id, 
     t.profile_id, 
     t.score, 
     t.pubdate_utc 
FROM (SELECT p.profile_id, 
      p.post_id, 
      p.pubdate_utc, 
      (pp.comments + pp.likes + pp.favorites) score 
     FROM posts p 
     JOIN posts_points pp ON p.post_id = pp.post_id 
     WHERE p.pubdate_utc >= DATE_ADD(DATE(NOW()), INTERVAL -17 DAY) 
     ORDER BY score DESC 
    ) t 
GROUP BY DATE(t.pubdate_utc) DESC 
; 

Zauważ, że nie używam tutaj funkcji MAX. Zamawianie według wyniku malejącego, a następnie grupowania według daty w zapytaniu zewnętrznym, spowoduje najwyższy wynik według daty. Zauważ też, że umieszczam klauzulę WHERE w zapytaniu wewnętrznym. Wewnętrzne zapytania, takie jak te (czasami konieczne), nie są zbyt wydajne, ponieważ nie mają indeksów dla zewnętrznej kwerendy do optymalizacji, więc upewnij się, że Twój wewnętrzny zestaw wyników jest tak mały, jak tylko może być. Wreszcie, należy zwrócić uwagę na GROUP BY DATE (t.pubdate_utc). Gdybym nie zredukował tego do informacji o dacie, byłoby znacznie więcej niż 18 wyników, ponieważ wtedy również są liczone czasy.

Edycja: Zmieniono INTERVAL -17 DAY zrezygnować do 18 wyników zamiast 19.