sql >> Database >  >> RDS >> Mysql

Hoe FIND_IN_SET te gebruiken met behulp van de lijst met gegevens

Overweeg allereerst om de gegevens op een genormaliseerde manier op te slaan. Hier is goed te lezen:Is het echt zo erg om een ​​gescheiden lijst in een databasekolom op te slaan?

Nu - Uitgaande van het volgende schema en de volgende gegevens:

create table products (
  id int auto_increment,
  upc varchar(50),
  upc_variation text,
  primary key (id),
  index (upc)
);
insert into products (upc, upc_variation) values
  ('01234', '01234,12345,23456'),
  ('56789', '45678,34567'),
  ('056789', '045678,034567');

We willen producten vinden met variaties '12345' en '34567' . Het verwachte resultaat is de 1e en de 2e rij.

Genormaliseerd schema - veel-op-veel-relatie

In plaats van de waarden op te slaan in een door komma's gescheiden lijst, maakt u een nieuwe tabel, waarin product-ID's met variaties worden toegewezen:

create table products_upc_variations (
  product_id int,
  upc_variation varchar(50),
  primary key (product_id, upc_variation),
  index  (upc_variation, product_id)
);
insert into products_upc_variations (product_id, upc_variation) values 
  (1, '01234'),
  (1, '12345'),
  (1, '23456'),
  (2, '45678'),
  (2, '34567'),
  (3, '045678'),
  (3, '034567');

De selectievraag zou zijn:

select distinct p.*
from products p
join products_upc_variations v on v.product_id = p.id
where v.upc_variation in ('12345', '34567');

Zoals je ziet - Met een genormaliseerd schema kan het probleem worden opgelost met een vrij eenvoudige vraag. En we kunnen indices effectief gebruiken.

'Exploitatie' van een FULLTEXT INDEX

Met een FULLTEXT INDEX op (upc_variation) je kunt gebruiken:

select p.*
from products p
where match (upc_variation) against ('12345 34567');

Dit ziet er behoorlijk "mooi" uit en is waarschijnlijk efficiënt. Maar hoewel het voor dit voorbeeld werkt, zou ik me niet op mijn gemak voelen bij deze oplossing, omdat ik niet precies kan zeggen wanneer het niet werkt.

JSON_OVERLAPS() gebruiken

Sinds MySQL 8.0.17 kun je JSON_OVERLAPS() . U moet de waarden ofwel opslaan als een JSON-array, of de lijst "on the fly" naar JSON converteren:

select p.*
from products p
where json_overlaps(
  '["12345","34567"]',
  concat('["', replace(upc_variation, ',', '","'), '"]')
);

Hiervoor kan geen index worden gebruikt. Maar geen van beide kan voor FIND_IN_SET() .

JSON_TABLE() gebruiken

Sinds MySQL 8.0.4 kun je JSON_TABLE() gebruiken om een ​​genormaliseerde weergave van de gegevens "on the fly" te genereren. Ook hier zou u ofwel de gegevens in een JSON-array opslaan, of de lijst in de query naar JSON converteren:

select distinct p.*
from products p
join json_table(
  concat('["', replace(p.upc_variation, ',', '","'), '"]'),
  '$[*]' columns (upcv text path '$')
) v
where v.upcv in ('12345', '34567');

Hier kan geen index worden gebruikt. En dit is waarschijnlijk de langzaamste oplossing die in dit antwoord wordt gepresenteerd.

RLIKE / REGEXP

U kunt ook een gewone uitdrukking gebruiken :

select p.*
from products p
where p.upc_variation rlike '(^|,)(12345|34567)(,|$)'

Bekijk de demo van alle zoekopdrachten op dbfiddle.uk



  1. Een-op-veel-relatie in MySQL - hoe een model te bouwen?

  2. Hoe ROWNUM werkt in een paginatiequery?

  3. Mysql_real_escape_string() Waarschuwing Verwarring

  4. De beste manier om zoekopdrachten van gebruikers in ElasticSearch op te slaan?