mySQL ›› Нормализация поля с разделителями-запятыми

В настоящее время у меня есть таблица под названием «RESOURCES» с полем ключевых слов под названием «RES_Tags». Поле «RES_Tags» содержит разделенный запятыми список ключевых слов для каждой записи.

Мне нужно нормализовать эту таблицу/поле.

Я уже настроил следующие таблицы: TAGS, TAGS_TO_RESOURCES.

См. схему здесь: http://sqlfiddle.com/#!9/edac4/1< /а>

Какой запрос позволит мне проанализировать ключевые слова в RES_Tags, записать их в таблицу TAGS без создания дубликатов, а затем записать список в таблицу TAGS_TO_RESOURCES?


person nbardach    schedule 08.11.2017    source источник
comment
Честно говоря, я бы написал для этого небольшой скрипт на Python. Извлеките каждую строку из tags.res_tags, разбейте строку на массив и запустите цикл, чтобы вставить несколько строк в новую таблицу, по одной строке на тег.   -  person Bill Karwin    schedule 09.11.2017
comment
Честно говоря, я думал сделать это в VBS (мой любимый вариант). Я могу использовать FOR EACH x IN RES_Tags, NEXT, LOOP, но я подумал, что, может быть, будет лучше перейти с конца БД. Еще на заборе....   -  person nbardach    schedule 09.11.2017
comment
Это тот случай, когда настолько неудобно выполнять задачу в SQL, что гораздо лучше сделать это в коде приложения. SQL с самого начала предназначался для использования в контексте кода приложения.   -  person Bill Karwin    schedule 09.11.2017
comment
Кроме того, версию SQL, как правило, намного сложнее поддерживать. Мой примерный код нужно было бы изменить (или сделать более сложным), чтобы он обрабатывал случаи, когда в столбец было втиснуто более шести элементов.   -  person Brian Dewhirst    schedule 10.11.2017
comment
Google '(отменить ИЛИ реверсировать ИЛИ инверсно) group_concat'. Это часто задаваемые вопросы.   -  person philipxy    schedule 10.11.2017
comment
Пожалуйста, используйте текст вместо текста, не используйте ссылки/изображения. Пожалуйста, прочитайте Как спросить и минимальный воспроизводимый пример и покажите, что вы исследовали и пробовали.   -  person philipxy    schedule 25.11.2017


Ответы (2)


Пожалуйста, скопируйте свой код в реальную публикацию и предоставьте код, который вы пытались использовать для решения проблемы.

Функция substring_index возвращает часть строки с некоторым разделителем (здесь запятая), и когда передается отрицательный индекс, она начинает поиск совпадений с противоположной стороны, поэтому -1 берет один элемент из того, что в противном случае было бы многоэлементным списком ( для индекса>=2).

Согласно нашему обсуждению, я подправил, как я это сделал, и показал пример использования автоинкремента. (Это запускается в части скрипки «Схема сборки».)

create table TAGS
(`T_ID` int auto_increment primary key, `T_Name` varchar(18))
;

insert ignore into TAGS (T_Name)
  SELECT 
    SUBSTRING_INDEX(RES_Tags, ',', 1) as X
    FROM RESOURCES
;

insert ignore into TAGS (T_Name)
  SELECT 
    SUBSTRING_INDEX(
      SUBSTRING_INDEX(RES_Tags, ',', 2)
      ,',',-1)
  FROM RESOURCES
;

insert ignore into TAGS (T_Name)
  SELECT 
    SUBSTRING_INDEX(
      SUBSTRING_INDEX(RES_Tags, ',', 3)
      ,',',-1)  as X
  FROM RESOURCES
;
insert ignore into TAGS (T_Name)
  SELECT 
    SUBSTRING_INDEX(
      SUBSTRING_INDEX(RES_Tags, ',', 4)
      ,',',-1)  as X
  FROM RESOURCES
  ;

insert ignore into TAGS (T_Name)
  SELECT 
    SUBSTRING_INDEX(
      SUBSTRING_INDEX(RES_Tags, ',', 5)
      ,',',-1)  as X
  FROM RESOURCES
;

insert ignore into TAGS (T_Name)
  SELECT 
    SUBSTRING_INDEX(
      SUBSTRING_INDEX(RES_Tags, ',', 6)
      ,',',-1)  as X
  FROM RESOURCES
;

create table New_TAGS like TAGS;
insert into New_TAGS (T_Name)
  select distinct trim(T_Name)
  from TAGS;

drop table TAGS;
rename table NEW_TAGS to TAGS;

документация функции подстроки Возможное дублирование этого вопроса

person Brian Dewhirst    schedule 08.11.2017
comment
Спасибо, Брайан! Как ваш запрос приведет к решению, которое я ищу (т.е. запись подстроки (если она уникальна) в таблицу TAGS и запись ссылки в таблицу TAGS_TO_RESOURCES)? - person nbardach; 09.11.2017
comment
Мой код возвращает 22 уникальных тега в таблице ресурсов. Если вы ожидаете, что теги будут повторно использоваться в списке (например, «яблоко» будет встречаться несколько раз во фруктах), вам нужно будет добавить group by 1 внизу. Какой код вы пытались ввести в таблицу тегов? В целом я знаю, о чем вы спрашиваете, но какова ваша предполагаемая логика для TAGS_TO_RESOURCES? - person Brian Dewhirst; 09.11.2017
comment
Еще раз спасибо, Брайан! 22 возвращенных тега уникальны, потому что я забыл включить дубликаты в такие теги, как. Я обновил скрипт SQL, чтобы включить дубликат (банан во фруктах и ​​хлебе). Когда я запускаю ваш запрос, он дважды возвращает банан. У вас есть решение для этого? Причина использования таблицы «многие ко многим» TAGS_TO_RESOURCES заключается в том, чтобы вернуть теги вместе с ресурсами, с которыми они ранее были связаны. Надеюсь, это имеет смысл. - person nbardach; 10.11.2017
comment
Я изменил свой код выше, чтобы удалить дубликаты. Вы, вероятно, захотите изменить структуру своих таблиц, чтобы использовать автоматическое увеличение ссылка на документацию. - person Brian Dewhirst; 10.11.2017

  1. на основе RESOURCES.RES_tags создать набор из INSERT ... INTO TAGS ... операторов. Предотвратите дублирование с помощью ограничения UNIQUE в TAGS и ON DUPLICATE KEY ... или с помощью INSERT ... SELECT ... NOT EXISTS():

а) добавить на лету какой-то символ в начало RES_tags и другой символ в конец (скажем, - в начало, + в конец) - но не сохранять его обратно в БД (a,b,c превратится в -a,b,c+)

б) заменить на лету каждый ',' на конец предыдущего оператора INSERT и начало следующего; заменить «-» на «только запуск», «+»; только с конечной частью (например, - заменяется на insert into tags(tag) values(", + становится '"), а , будет "), (", но для сохранения их уникальности потребуется добавить что-то, упомянутое в шаге № 1)

  1. выполнить SQL, сгенерированный #1 (например, insert into tags(tag) values("a"), ("b"), ("c"))

  2. связать объект с тегами, используя:

    INSERT INTO TAGS_TO_RESOURCES(resource_id, tag_id)
    SELECT RESOURCES.id, TAGS.id
    FROM RESOURCES
    INNER JOIN TAGS
    ON INSTR(CONCAT(',', RESOURCES.RES.tags, ','), CONCAT(',', TAGS.tag, ','))> 0   
    
person skyboyer    schedule 25.11.2017