sql >> Database teknologi >  >> RDS >> PostgreSQL

Opbevar multidimensional array i databasen:relationel eller multidimensional?

Hvis det er alt, du har brug for, kan du bruge en LIKE-søgning

VÆLG *FRA Tabel1WHERE CELLE SOM 'AEE%'; 

Med et indeks, der begynder med CELL dette er en rækkeviddekontrol, som er hurtig.

Hvis dine data ikke ser sådan ud, kan du oprette en sti kolonne, der ligner en mappesti og indeholder alle noder "på vej/sti" fra rod til elementet.

| id | CELLE | forældre_id | sti ||====|=======|============|===========|| 1 | A | NULL | 1/ || 2 | AA | 1 | 1/2/ || 3 | AAA | 2 | 1/2/3/ || 4 | AAC | 2 | 1/2/4/ || 5 | AB | 1 | 1/5/ || 6 | AE | 1 | 1/6/ | | 7 | AEA | 6 | 1/6/7/ || 8 | AEE | 6 | 1/6/8/ || 9 | AEEB | 8 | 1/6/8/9/ |

For at hente alle efterkommere af 'AE' (inklusive sig selv) ville din forespørgsel være

VÆLG *FRA træet tWHERE sti LIKE '1/6/%'; 

eller (MySQL-specifik sammenkædning)

VÆLG t.*FRA træet tCROSS JOIN træ r -- rootWHERE r.CELL ='AE' OG t.sti SOM CONCAT(r.sti, '%'); 

Resultat:

| id | CELLE | forældre_id | sti ||====|=======|============|===========|| 6 | AE | 1 | 1/6/ || 7 | AEA | 6 | 1/6/7/ || 8 | AEE | 6 | 1/6/8/ || 9 | AEEB | 8 | 1/6/8/9/ |

Demo

Ydeevne

Jeg har oprettet 100.000 rækker af falske data på MariaDB med sequence plugin ved hjælp af følgende script:

slip tabel, hvis der findes træ; CREATE TABLE tree ( `id` int primærnøgle, `CELL` varchar(50), `parent_id` int, `path` varchar(255), unikt indeks (`CELL` ), unikt indeks (`sti`));DROP TRIGGER HVIS FINDER `tree_after_insert`;DELIMITER //CREATE TRIGGER `tree_after_insert` FØR INSERT ON `tree` FOR HVER ROW BEGIN if new.id =1, så sæt new.path :='1/'; else set new.path :=concat((vælg sti fra træet hvor id =new.parent_id ), new.id, '/'); end if;END//DELIMITER;insert into tree vælg seq as id , conv(seq, 10, 36) as CELL , case when seq =1 then null else floor(rand(1) * (seq-1)) + 1 end as parent_id , null som sti fra seq_1_to_100000;DROP TRIGGER IF EXISTS `tree_after_insert`;-- runtime ~ 4 sek. 

Tests

Tæl alle elementer under roden:

VÆLG antal(*)FRA træet tCROSS JOIN træ r -- rootWHERE r.CELL ='1' OG t.sti SOM CONCAT(r.sti, '%');-- resultat:100000-- runtime:~ 30 ms 

Hent undertræelementer under en specifik node:

VÆLG t.*FRA træet tCROSS JOIN træ r -- rootWHERE r.CELL ='3B0' OG t.sti SOM CONCAT(r.sti, '%');-- runtime:~ 30 ms

Resultat:

| id | CELLE | forældre_id | sti ||========|======|============|=======================================|| 4284 | 3B0 | 614 | 1/4/11/14/614/4284/ || 6560 | 528 | 4284 | 1/4/11/14/614/4284/6560/ || 8054 | 67Q | 6560 | 1/4/11/14/614/4284/6560/8054/ || 14358 | B2U | 6560 | 1/4/11/14/614/4284/6560/14358/ || 51911 | 141Z | 4284 | 1/4/11/14/614/4284/51911/ || 55695 | 16Z3 | 4284 | 1/4/11/14/614/4284/55695/ || 80172 | 1PV0 | 8054 | 1/4/11/14/614/4284/6560/8054/80172/ || 87101 | 1V7H | 51911 | 1/4/11/14/614/4284/51911/87101/ |

PostgreSQL

Dette virker også for PostgreSQL. Kun strengsammenkædningssyntaksen skal ændres:

VÆLG t.*FRA træet tCROSS JOIN træ r -- rootWHERE r.CELL ='AE' OG t.sti SOM r.sti || '%'; 

Demo: sqlfiddle - rextester

Hvordan fungerer søgningen

Hvis du ser på testeksemplet, vil du se, at alle stier i resultatet begynder med '1/4/11/14/614/4284/'. Det er stien til undertræets rod med CELL='3B0' . Hvis stien kolonnen er indekseret, vil motoren finde dem alle effektivt, fordi indekset er sorteret efter sti . Det er som om du ønsker at finde alle de ord, der begynder med 'pol' i en ordbog med 100K ord. Du behøver ikke at læse hele ordbogen.



  1. MySQL:Indlejret GROUP_CONCAT

  2. Laravel $q->where() mellem datoer

  3. Hvordan får man vist alle metadata for kolonner i en tabel i Oracle-databasen?

  4. Find alle noder i en tilstødende listemodel med oracle connect by