Можете ли вы разделить / взорвать поле в запросе MySQL? - PullRequest
42 голосов
/ 23 января 2009

Мне нужно составить отчет о некоторых студенческих работах. Каждый из студентов принадлежит одному клиенту. Вот таблицы (упрощенно для этого вопроса).

CREATE TABLE  `clients` (
  `clientId` int(10) unsigned NOT NULL auto_increment,
  `clientName` varchar(100) NOT NULL default '',
  `courseNames` varchar(255) NOT NULL default ''
)

Поле courseNames содержит разделенную запятыми строку названий курсов, например, "AB01, AB02, AB03"

CREATE TABLE  `clientenrols` (
  `clientEnrolId` int(10) unsigned NOT NULL auto_increment,
  `studentId` int(10) unsigned NOT NULL default '0',
  `courseId` tinyint(3) unsigned NOT NULL default '0'
)

Поле courseId здесь - индекс названия курса в поле clients.courseNames . Таким образом, если courseNames клиента - "AB01, AB02, AB03", а courseId зачисления - 2, то студент находится в AB03.

Есть ли способ, которым я могу сделать один выбор для этих таблиц, который включает название курса? Помните, что будут студенты из разных клиентов (и, следовательно, у них будут разные названия курсов, не все из которых являются последовательными, например: «NW01, NW03»)

В принципе, если бы я мог разделить это поле и вернуть один элемент из полученного массива, это было бы тем, что я искал. Вот что я имею в виду в магическом псевдокоде:

SELECT e.`studentId`, SPLIT(",", c.`courseNames`)[e.`courseId`]
FROM ...

Ответы [ 16 ]

2 голосов
/ 23 января 2009

Есть более простой способ, есть таблица ссылок, т.е.:

.

Таблица 1: клиенты, информация о клиенте, бла-бла-бла

Таблица 2: курсы, информация о курсе, бла-бла

Таблица 3: клиент, курс

Затем присоединяйтесь, и вы отправитесь на гонки.

1 голос
/ 22 апреля 2015

У меня просто была похожая проблема с таким полем, которую я решил по-другому. Мой сценарий использования должен был взять эти идентификаторы в списке через запятую для использования в объединении.

Мне удалось решить эту проблему с помощью аналога, но это стало проще, потому что в дополнение к разделителю запятых идентификаторы также были указаны так:

keys "1","2","6","12"

Из-за этого я смог сделать ЛАЙК

SELECT twwf.id, jtwi.id joined_id FROM table_with_weird_field twwf INNER JOIN join_table_with_ids jtwi ON twwf.delimited_field LIKE CONCAT("%\"", jtwi.id, "\"%")

Это просто выглядит, чтобы увидеть, появляется ли идентификатор из таблицы, к которой вы пытаетесь присоединиться, в наборе, и в этот момент вы можете присоединиться к нему достаточно легко и вернуть свои записи. Вы также можете просто создать вид из чего-то подобного.

Это хорошо сработало для моего случая использования, когда я имел дело с плагином Wordpress, который управлял отношениями описанным способом. Кавычки действительно помогают, потому что в противном случае вы рискуете получить частичное совпадение (aka - id 1 в пределах 18 и т. Д.).

1 голос
/ 29 апреля 2012

Я использовал вышеуказанную логику, но немного ее изменил. Мой вход имеет формат: "apple: 100 | pinapple: 200 | orange: 300", хранящиеся в переменной @ updtAdvanceKeyVal

Вот функциональный блок:

set @res = "";

set @i = 1;
set @updtAdvanceKeyVal = updtAdvanceKeyVal;

REPEAT


 -- set r =  replace(SUBSTRING(SUBSTRING_INDEX(@updtAdvanceKeyVal, "|", @i),
 --  LENGTH(SUBSTRING_INDEX(@updtAdvanceKeyVal, "|", @i -1)) + 1),"|","");

-- wrapping the function in "replace" function as above causes to cut off a character from
 -- the 2nd splitted value if the value is more than 3 characters. Writing it in 2 lines causes no such problem and the output is as expected
-- sample output by executing the above function :
-- orange:100
-- pi apple:200    !!!!!!!!strange output!!!!!!!!
-- tomato:500

      set @r =  SUBSTRING(SUBSTRING_INDEX(@updtAdvanceKeyVal, "|", @i),
                  LENGTH(SUBSTRING_INDEX(@updtAdvanceKeyVal, "|", @i -1)) + 1);

      set @r = replace(@r,"|","");

      if @r <> "" then

              set @key = SUBSTRING_INDEX(@r, ":",1);
              set @val = SUBSTRING_INDEX(@r, ":",-1);

              select @key, @val;
      end if;

      set @i = @i + 1;

     until @r = ""
END REPEAT;
0 голосов
/ 14 августа 2013

Ну, ничего, что я использовал, не сработало, поэтому я решил создать очень простую функцию разделения, надеюсь, она поможет:

    DECLARE inipos INTEGER;
    DECLARE endpos INTEGER;
    DECLARE maxlen INTEGER;
    DECLARE item VARCHAR(100);
    DECLARE delim VARCHAR(1);

    SET delim = '|';
    SET inipos = 1;
    SET fullstr = CONCAT(fullstr, delim);
    SET maxlen = LENGTH(fullstr);

    REPEAT
        SET endpos = LOCATE(delim, fullstr, inipos);
        SET item =  SUBSTR(fullstr, inipos, endpos - inipos);

        IF item <> '' AND item IS NOT NULL THEN           
            USE_THE_ITEM_STRING;
        END IF;
        SET inipos = endpos + 1;
    UNTIL inipos >= maxlen END REPEAT;
0 голосов
/ 23 января 2009

Вот что я получил (нашел на странице Бен Альперт упомянул):

SELECT REPLACE(
    SUBSTRING(
        SUBSTRING_INDEX(c.`courseNames`, ',', e.`courseId` + 1)
        , LENGTH(SUBSTRING_INDEX(c.`courseNames`, ',', e.`courseId`)
    ) + 1)
    , ','
    , ''
)
FROM `clients` c INNER JOIN `clientenrols` e USING (`clientId`)
0 голосов
/ 23 января 2009

Вот как вы это делаете для SQL Server. Кто-то еще может перевести его на MySQL. Разбор значений CSV в несколько строк .

SELECT Author, 
NullIf(SubString(',' + Phrase + ',' , ID , CharIndex(',' , ',' + Phrase + ',' , ID) - ID) , '') AS Word 
FROM Tally, Quotes 
WHERE ID <= Len(',' + Phrase + ',') AND SubString(',' + Phrase + ',' , ID - 1, 1) = ',' 
AND CharIndex(',' , ',' + Phrase + ',' , ID) - ID > 0

Идея заключается в перекрестном соединении с предопределенной таблицей Tally, которая содержит целое число от 1 до 8000 (или любое другое достаточно большое число), и запустите SubString, чтобы найти нужное слово, слово, позицию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...