считайте значение из столбца и выполните запрос на основе этого

#mysql #sql #database #select

Вопрос:

У меня есть таблица с 2 столбцами в моей базе данных: name и families , и оба они есть varchar . например:

 name     families
----------------------
A        'B','C'
B        'A'
C        'A','B'
...
 

теперь я хочу получить строки, имена которых указаны в столбце семейства первой строки. Я пытался:

 SELECT * FROM t JOIN (SELECT families FROM t WHERE name='A') AS z WHERE name IN (z.families)
 

но он не возвращает ни одной строки. в чем проблема?

Комментарии:

1. Исправьте свою модель данных! Не храните несколько значений в одном столбце!

2. @Гордон итак, каков наилучший подход в моем случае? как вы можете видеть, семейства не являются уникальными, например B , в столбце семейства обоих A и C

Ответ №1:

У вас должна быть таблица с одной строкой на имя и семью:

 name   family
 A       B
 A       C
 B       A
. . . 
 

Тогда ваш запрос просто:

 select nf.*
from name_families nf join
     name_families nf2
     on nf2.family= nf.family and
        nf2.name = 'A' and
        nf2.name <> fn.name;
 

Комментарии:

1. к сожалению, в моем случае это абсолютно невозможно. у каждого человека (имени) может быть только одна строка из-за некоторых ограничений.

2. @Soheil . . . Это было бы в другой таблице.

3. да, отношение «многие ко многим» может быть реализовано таким образом, но наше ограничение также состоит в том, чтобы избежать дополнительной таблицы. у нас есть миллионы строк, и эта дополнительная таблица создаст чрезвычайно большое количество строк. почему просто данные, хранящиеся в одном столбце, не могут быть использованы в моем запросе (например, то, о чем я упоминал в вопросе)?

Ответ №2:

Используйте функцию FIND_IN_SET() в самостоятельном соединении, как это:

 SELECT DISTINCT t1.name
FROM t t1 INNER JOIN t t2
ON FIND_IN_SET(t1.name, REPLACE(t2.families, '''', ''))
WHERE t2.name = 'A'
 

Или:

 SELECT DISTINCT t1.name
FROM t t1 INNER JOIN t t2
ON FIND_IN_SET(QUOTE(t1.name), t2.families)
WHERE t2.name = 'A'
 

Или без соединения:

 SELECT name
FROM t 
WHERE FIND_IN_SET(QUOTE(name), (SELECT families FROM t WHERE name = 'A'))
 

Смотрите демонстрацию.
Результаты:

Имя
B
C

Комментарии:

1. большое спасибо. но данные в столбце «семьи» сохраняются в следующем формате: «A»,»B»,… (обратите внимание на цитаты!)

2. @Soheil Я этого не заметил, и это странно. Смотрите мой отредактированный ответ.