Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jak korzystać z FIND_IN_SET przy użyciu listy danych?

Przede wszystkim rozważ przechowywanie danych w znormalizowany sposób. Oto dobra lektura:Czy przechowywanie rozdzielanej listy w kolumnie bazy danych jest naprawdę takie złe?

Teraz — zakładając następujący schemat i dane:

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');

Chcemy znaleźć produkty z odmianami '12345' i '34567' . Oczekiwany wynik to pierwszy i drugi wiersz.

Schemat znormalizowany — relacja wiele-do-wielu

Zamiast przechowywać wartości na liście oddzielonej przecinkami, utwórz nową tabelę, która mapuje identyfikatory produktów z odmianami:

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');

Zapytanie wybierające to:

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

Jak widać - przy znormalizowanym schemacie problem można rozwiązać za pomocą dość podstawowego zapytania. I możemy efektywnie korzystać z indeksów.

„Wykorzystywanie” indeksu PEŁNOTEKSTOWEGO

Z INDEKSEM PEŁNOTEKSTOWYM na (upc_variation) możesz użyć:

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

Wygląda to całkiem „ładnie” i prawdopodobnie jest wydajne. Ale chociaż to działa w tym przykładzie, nie czułbym się komfortowo z tym rozwiązaniem, ponieważ nie mogę dokładnie powiedzieć, kiedy to nie działa.

Korzystanie z JSON_OVERLAPS()

Od wersji MySQL 8.0.17 możesz używać JSON_OVERLAPS() . Powinieneś albo przechowywać wartości jako tablicę JSON, albo przekonwertować listę na JSON „w locie”:

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

Żaden indeks nie może być do tego użyty. Ale nie może też dla FIND_IN_SET() .

Korzystanie z JSON_TABLE()

Od MySQL 8.0.4 możesz używać JSON_TABLE() do generowania znormalizowanej reprezentacji danych „w locie”. Tutaj ponownie albo przechowasz dane w tablicy JSON, albo przekonwertujesz listę na JSON w zapytaniu:

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');

Nie można tutaj użyć indeksu. I jest to prawdopodobnie najwolniejsze rozwiązanie ze wszystkich przedstawionych w tej odpowiedzi.

RLIKE / REGEXP

Możesz także użyć wyrażenia regularnego :

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

Zobacz demo wszystkich zapytań na dbfiddle.uk



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Instalator MySql 5.7 nie wykrywa pakietu redystrybucyjnego VS 2013

  2. Wyliczanie tabel używanych w zapytaniu mysql?

  3. Wyzwalacz w mysql powodujący błąd

  4. Problemy z wstawianiem ciągu utf-8 do bazy danych, a następnie wysyłaniem go na stronę internetową

  5. MySQL:jak posortować słowa w ciągu za pomocą funkcji przechowywanej?