I have a table with webpage data that looks somewhat like this:
row_id ⁞ page_id ⁞ lang ⁞ title ⁞ slug ────────┼─────────┼──────┼────────────────────┼──────────────── 1 ⁞1 ⁞ en ⁞ Welcome! ⁞ begin 2 ⁞1 ⁞ fr ⁞ Bienvenue! ⁞ bienvenue 3 ⁞2 ⁞ pl ⁞ Podstrona ⁞ podstrona 4 ⁞2 ⁞ en ⁞ Subpage ⁞ subpage 5 ⁞3 ⁞ pl ⁞ Podstrona 2 ⁞ podstrona-2 6 ⁞4 ⁞ fr ⁞ Coordonnées ⁞ coordonnees 7 ⁞5 ⁞ pl ⁞ Podstrona poziom 2 ⁞ podstrona-lvl-2 8 ⁞5 ⁞ en ⁞ Subpage Lvl 2 ⁞ subpage-lvl-2 9 ⁞6 ⁞ pl ⁞ Poziom 3 ⁞ poziom-3 10 ⁞6 ⁞ en ⁞ Level 3 ⁞ lvl-3 11 ⁞7 ⁞ pl ⁞ Błąd 404 ⁞ 404 12 ⁞7 ⁞ en ⁞ Error 404 ⁞ 404 13 ⁞7 ⁞ fr ⁞ Erreur 404 ⁞ 404
I want to fetch a single language version of each page in a prioritized order. Let’s say I’d like to fetch all pages of fr language, but if some pages lack that language version, then get the en version instead, but again if there’s no en, try pl, and so on; so in this case the result would look like this:
row_id ⁞ page_id ⁞ lang ⁞ title ⁞ slug ────────┼─────────┼──────┼────────────────────┼──────────────── 2 ⁞1 ⁞ fr ⁞ Bienvenue! ⁞ bienvenue 4 ⁞2 ⁞ en ⁞ Subpage ⁞ subpage 5 ⁞3 ⁞ pl ⁞ Podstrona 2 ⁞ podstrona-2 6 ⁞4 ⁞ fr ⁞ Coordonnées ⁞ coordonnees 8 ⁞5 ⁞ en ⁞ Subpage Lvl 2 ⁞ subpage-lvl-2 10 ⁞6 ⁞ en ⁞ Level 3 ⁞ lvl-3 13 ⁞7 ⁞ fr ⁞ Erreur 404 ⁞ 404
The language count is not predifined, however each page is bound to have at least one language version.
It’s possible to do with a whoopload of queries, or by fetching all the data and then process it programatically by PHP, but I was wondering if there is an elegant SQL (SQLite) solution that would solve this in one query?
Advertisement
Answer
With conditional aggregation:
select t.* from ( select page_id, max(lang ='fr') fr, max(lang ='en') en, max(lang ='pl') pl from tablename group by page_id ) g inner join tablename t on t.page_id = g.page_id and t.lang = case 1 when g.fr then 'fr' when g.en then 'en' when g.pl then 'pl' end
See the demo.
Or if your version of SQLite allows the use of window functions:
with cte(id, lang) as ( select * from (values (1, 'fr'), (2, 'en'), (3, 'pl')) ), langs as ( select t.*, row_number() over (partition by t.page_id order by c.id) rn from cte c inner join tablename t on t.lang = c.lang ) select row_id, page_id, lang, title, slug from langs where rn = 1 order by page_id
See the demo.
Results:
| row_id | page_id | lang | title | slug | | ------ | ------- | ---- | ------------- | ------------- | | 2 | 1 | fr | Bienvenue! | bienvenue | | 4 | 2 | en | Subpage | subpage | | 5 | 3 | pl | Podstrona 2 | podstrona-2 | | 6 | 4 | fr | Coordonnées | coordonnees | | 8 | 5 | en | Subpage Lvl 2 | subpage-lvl-2 | | 10 | 6 | en | Level 3 | lvl-3 | | 13 | 7 | fr | Erreur 404 | 404 |