Laatste vijf artikelen ophalen uit alle categoriëen

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

- Ariën  -
Beheerder

- Ariën -

16/05/2022 00:46:16
Quote Anchor link
Ik was even benieuwd of iemand een mooie handige query zou weten om de laatste vijf artikelen op te halen uit alle categoriëen, en hierbij te groeperen op de categorie. Ik krijg het niet voor elkaar na wat geklooid te hebben van GROUP BY en zelfs HAVING.

Momenteel heb ik dit stukje oude code waarbij ik dus een query uitvoer met in het statement een extra query.
Resultaat: met 8 categorieën dus 9 queries. Dit wil ik dus -als het kán- omlaag brengen naar één query.

En zo een resultaat wil ik eruit halen, en de enter halverwege heb ik even voor het overzicht geplaatst.

Title - DateCreation - Category
-----------------------------

Bla die bla - 11-5-2022 - Categorie A
Bla die bla - 12-5-2022 - Categorie A
Bla die bla - 13-5-2022 - Categorie A
Bla die bla - 14-5-2022 - Categorie A
Bla die bla - 15-5-2022 - Categorie A

Bla die bla - 11-5-2022 - Categorie B
Bla die bla - 12-5-2022 - Categorie B
Bla die bla - 13-5-2022 - Categorie B
Bla die bla - 14-5-2022 - Categorie B
Bla die bla - 15-5-2022 - Categorie B


Dit stukje code heb ik momenteel, maar er moet toch een query mogelijk zijn om bovenstaand resultaat te krijgen, zodat ik die tweede whileloop kan laten vervallen?

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<?php
    $data
= array();
    $result_cats = $db->query("SELECT ID, Title, Keyword FROM news_categories");
    while ($newscat = $result_cats->fetch_assoc()) {
    $sql = "SELECT ID, Title, DateCreation, Author FROM news_articles WHERE catID ='" . $db->real_escape_string($newscat['ID']) . "' AND concept=0 ORDER BY DateCreation DESC LIMIT 5";
    $result_items = $db->query($sql);
    while ($item = $result_items->fetch_assoc()) {
        $item['slug'] = $slug->create($item['Title']);
        $data[$newscat['Title']][] = $item;
    }
    }

?>
Gewijzigd op 16/05/2022 00:47:23 door - Ariën -
 
PHP hulp

PHP hulp

27/06/2022 17:09:19
 
Ward van der Put
Moderator

Ward van der Put

16/05/2022 09:52:55
 
Ad Fundum

Ad Fundum

16/05/2022 11:06:51
Quote Anchor link
Als je de mogelijkheid hebt (MySQL 8+) kan je ook een window-functie gebruiken die een rijnummer aanmaakt per groep, zodat je in de WHERE al kan zeggen dat je alleen de eerste X rijen wilt.

Want wanneer je het met een HAVING doet, moet de database eerst alle rijen evalueren en dat pakt nadelig uit voor de performance.
 
Spike Spade

Spike Spade

16/05/2022 13:25:43
Quote Anchor link
Zoiets?

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
select `title`, cat, wanneer
from
    (
        select `title`, cat, `DateCreation`,
               (@rn:=if(@prev = cat, @rn +1, 1)) as rownumb,
               @prev:= cat
        from
            (
            SELECT `title`, cat, `DateCreation`
            FROM {table_name}
            ORDER BY cat ,  `DateCreation` desc, `title`
            )   as sortedlist
            JOIN (select @prev:=NULL, @rn :=0) as vars
            ORDER BY cat, `DateCreation`
    ) as groupedlist
WHERE rownumb<=5
ORDER BY cat , `DateCreation` desc, `title`;
Gewijzigd op 16/05/2022 14:05:26 door Spike Spade
 
Adoptive Solution

Adoptive Solution

16/05/2022 16:20:22
Quote Anchor link
Hier wat voorbeelden :

https://www.sqlines.com/mysql/how-to/get_top_n_each_group

De SQL code (MariaDB 10) volgens het laatste voorbeeld :

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SELECT
    mk.brand AS brand,
    models.model AS model
FROM (
    SELECT
        models.brand_id AS brand_id,
        models.model AS model,
        row_number() over ( partition by models.brand_id
    ORDER BY
        models.brand_id DESC ) AS mobiel_rank
    FROM models ) ranked

LEFT JOIN
    make mk
ON
    mk.id = brand_id

WHERE
    mobiel_rank <= 5 AND brand_id <= 20; # aanpassen naar behoefte


Je zou er een VIEW of een STORED PROCEDURE van kunnen maken.

De bijbehorende database :

https://github.com/VinceG/Auto-Cars-Makes-And-Models
Gewijzigd op 16/05/2022 16:23:04 door Adoptive Solution
 
- Ariën  -
Beheerder

- Ariën -

16/05/2022 20:35:18
Quote Anchor link
Thanks voor de reacties. Ik ga er morgen even naar kijken en uitzoeken hoe dit werkt. ;-)
 
Ad Fundum

Ad Fundum

17/05/2022 10:58:07
Quote Anchor link
Het zou leuk zijn als ik gelijk heb over de performance, maar al proberend (ik probeer MySQL te vermijden zoals ik wel eens heb laten weten :-)) kwam ik een nare melding tegen:

#4015 - Window function is allowed only in SELECT list and ORDER BY clause

Uiteindelijk kwam ik uit op iets als dit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[mysql]
WITH testtabel AS (
  SELECT 'a' AS categorie, 1 AS nummer
  UNION SELECT 'a', 2
  UNION SELECT 'a', 3
  UNION SELECT 'b', 4
  UNION SELECT 'b', 5
  UNION SELECT 'b', 6
), gesorteerd AS (
  SELECT testtabel.*,
    ROW_NUMBER() OVER (
      PARTITION BY categorie
      ORDER BY nummer DESC
    ) AS rn
  FROM testtabel
)
SELECT categorie, nummer
FROM gesorteerd
WHERE rn < 3;
[/mysql]

Teruglezend is dat dezelfde oplossing als wat Adoptive Solution schreef, maar dan met CTE in plaats van nested SELECTs. Dus die van Adoptive Solution is beter, omdat die ook met eerdere versies van MySQL werkt.
Gewijzigd op 17/05/2022 15:01:32 door Ad Fundum
 
- Ariën  -
Beheerder

- Ariën -

17/05/2022 11:03:59
Quote Anchor link
Het punt is wel dat ik een recente MariaDB gebruik. Ik ga ervanuit dat dit ook daarop zal werken gezien het een fork is.
 
Ad Fundum

Ad Fundum

17/05/2022 15:00:23
Quote Anchor link
Ja het werkt op MariaDB 10.3.
Daarmee had ik het getest, het is wat er op mijn bijna verouderde Synology NAS staat, maak je geen zorgen.
Gewijzigd op 17/05/2022 15:02:01 door Ad Fundum
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.