sql >> Database >  >> RDS >> PostgreSQL

Multidimensionale array opslaan in database:relationeel of multidimensionaal?

Als dat alles is wat je nodig hebt, kun je een LIKE-zoekopdracht gebruiken

SELECT *
FROM Table1
WHERE CELL LIKE 'AEE%';

Met een index die begint met CELL dit is een bereikcontrole, die snel is.

Als uw gegevens er niet zo uitzien, kunt u een path . maken kolom die eruitziet als een directorypad en alle knooppunten bevat "op de weg/het pad" van root naar het element.

| id | CELL | parent_id | path     |
|====|======|===========|==========|
|  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/ |

Om alle afstammelingen van 'AE' (inclusief zichzelf) op te halen, zou uw vraag zijn

SELECT *
FROM tree t
WHERE path LIKE '1/6/%';

of (MySQL-specifieke aaneenschakeling)

SELECT t.*
FROM tree t
CROSS JOIN tree r -- root
WHERE r.CELL = 'AE'
  AND t.path LIKE CONCAT(r.path, '%');

Resultaat:

| id | CELL | parent_id |     path |
|====|======|===========|==========|
|  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

Prestaties

Ik heb 100.000 rijen met nepgegevens gemaakt op MariaDB met de sequentie-plug-in met het volgende script:

drop table if exists tree;
CREATE TABLE tree (
  `id` int primary key,
  `CELL` varchar(50),
  `parent_id` int,
  `path` varchar(255),
  unique index (`CELL`),
  unique index (`path`)
);

DROP TRIGGER IF EXISTS `tree_after_insert`;
DELIMITER //
CREATE TRIGGER `tree_after_insert` BEFORE INSERT ON `tree` FOR EACH ROW BEGIN
    if new.id = 1 then
        set new.path := '1/';
    else    
        set new.path := concat((
            select path from tree where id = new.parent_id
        ), new.id, '/');
    end if;
END//
DELIMITER ;

insert into tree
    select 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 as path
    from seq_1_to_100000
;
DROP TRIGGER IF EXISTS `tree_after_insert`;
-- runtime ~ 4 sec.

Testen

Tel alle elementen onder de wortel:

SELECT count(*)
FROM tree t
CROSS JOIN tree r -- root
WHERE r.CELL = '1'
  AND t.path LIKE CONCAT(r.path, '%');
-- result: 100000
-- runtime: ~ 30 ms

Haal substructuurelementen op onder een specifiek knooppunt:

SELECT t.*
FROM tree t
CROSS JOIN tree r -- root
WHERE r.CELL = '3B0'
  AND t.path LIKE CONCAT(r.path, '%');
-- runtime: ~ 30 ms

Resultaat:

| id    | CELL | parent_id | path                                |
|=======|======|===========|=====================================|
|  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

Dit werkt ook voor PostgreSQL. Alleen de syntaxis van de aaneenschakeling van tekenreeksen hoeft te worden gewijzigd:

SELECT t.*
FROM tree t
CROSS JOIN tree r -- root
WHERE r.CELL = 'AE'
  AND t.path LIKE r.path || '%';

Demo: sqlfiddle - rextester

Hoe werkt het zoeken

Als u naar het testvoorbeeld kijkt, ziet u dat alle paden in het resultaat beginnen met '1/4/11/14/614/4284/'. Dat is het pad van de subboom root met CELL='3B0' . Als het path kolom is geïndexeerd, zal de engine ze allemaal efficiënt vinden, omdat de index is gesorteerd op path . Het is alsof je alle woorden die beginnen met 'pol' wilt vinden in een woordenboek met 100.000 woorden. Je zou niet het hele woordenboek hoeven te lezen.



  1. PostgreSQL Client v10 installeren op AWS Amazon Linux (EC2) AMI

  2. MySQL GROUP door of met PHP?

  3. Fatale fout:oproep naar ongedefinieerde functie getRecords() in C:\xampp\htdocs\Employees.php op regel 101

  4. Hoe duplicaten in de SQL-tabel te verwijderen op basis van meerdere velden