Как взорвать строку в mysql и получить каждое значение? [Дубликат]

Чтобы определить, почему код PHP не работает в коде JavaScript , нам нужно понять, что такое клиентский и серверный язык и как они работают.

Серверные языки (PHP и т. д.) : они извлекают записи из баз данных, поддерживают состояние через HTTP-соединение без состояния и выполняют много вещи, требующие безопасности. Они находятся на сервере, эти программы никогда не имеют своего исходного кода для пользователя

Image from wikipedia_http://en.wikipedia.org/wiki/File:Scheme_dynamic_page_en.svg [/g16] image attr

Хотя с другой стороны Клиентский язык на стороне клиента (например, JavaScript) находится в браузере и запускается в браузере, Сценарии на стороне клиента обычно относятся к классу компьютерных программ в Интернете, которые выполняются на стороне клиента, в веб-браузере пользователя, а не на стороне сервера .

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

Итак, когда вы делаете запрос HTTP на сервере, чем сервер, сначала внимательно читает файл PHP, чтобы узнать, есть ли какие-либо задачи, которые необходимо выполнить, и отправлять ответ на клиентскую сторону и снова, как @deceze сказал * Как только PHP закончил вывод ответа, сценарий заканчивается, и на сервере ничего не произойдет, пока не появится новый запрос HTTP . *

Graphical representation [/g17]

Источник изображения

Итак, что мне делать, если мне нужно вызвать PHP? Это зависит от того, как вам это нужно: либо перезагружая страницу, либо используя вызов AJAX.

  1. Вы можете выполнить перезагрузку страницы и отправить запрос HTTP
  2. вы можете сделать вызов AJAX с помощью JavaScript, и это не требует перезагрузки страницы

Хорошо Чтение:

  1. Википедия:
  2. Википедия: скрипты на стороне клиента
  3. Мадара Учиха: разница между клиентской стороной и программированием на стороне сервера

41
задан nickf 23 January 2009 в 05:53
поделиться

14 ответов

Основываясь на решении Альвина Кеслера, вот пример более практичного реального мира.

Предполагая, что список, разделенный запятыми, находится в my_table.list, и это список идентификаторов для my_other_table.id, вы можете сделать что-то вроде:

SELECT 
    * 
FROM 
    my_other_table 
WHERE 
    (SELECT list FROM my_table WHERE id = '1234') REGEXP CONCAT(',?', my_other_table.id, ',?');
4
ответ дан Alex Stevenson 26 August 2018 в 20:17
поделиться
  • 1
    Хорошее решение, но как мы можем избавиться от этого параметра id = '1234'? Я имею в виду, я хочу извлечь значения для всех записей my_table, а не только одного. – DarkSide 26 March 2014 в 19:40

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

SELECT * 
FROM `TABLE`
WHERE `field` REGEXP ',?[SEARCHED-VALUE],?';

, жадный вопросительный знак помогает искать в начале или в конце строки.

Надеюсь, что это поможет любому в будущем

4
ответ дан Alwin Kesler 26 August 2018 в 20:17
поделиться

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

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

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

Из-за этого я смог сделать LIKE

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
ответ дан brightball 26 August 2018 в 20:17
поделиться

Вот что я получил до сих пор (нашел его на странице Ben Alpert ):

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`)
7
ответ дан Community 26 August 2018 в 20:17
поделиться
  • 1
    Отредактировано, чтобы не использовать ',?' в regexp, но используйте проверку границ слов [[:<:]]word[[:>:]]. В противном случае из значения "WEB" он может извлекать более одного значения - например, E или B или EB или WE (любая комбинация). – DarkSide 27 March 2014 в 18:36
  • 2
    В MySQL, если это поле с разделителями-запятыми, было бы более эффективным использовать FIND_IN_SET, а не регулярное выражение для соединения. – Kickstart 19 June 2014 в 12:15
  • 3
    @Kickstart, конечно – DarkSide 19 June 2014 в 23:32
SELECT
  tab1.std_name, tab1.stdCode, tab1.payment,
  SUBSTRING_INDEX(tab1.payment, '|', 1) as rupees,
  SUBSTRING(tab1.payment, LENGTH(SUBSTRING_INDEX(tab1.payment, '|', 1)) + 2,LENGTH(SUBSTRING_INDEX(tab1.payment, '|', 2))) as date
FROM (
  SELECT DISTINCT
    si.std_name, hfc.stdCode,
    if(isnull(hfc.payDate), concat(hfc.coutionMoneyIn,'|', year(hfc.startDtae), '-',  monthname(hfc.startDtae)), concat(hfc.payMoney, '|', monthname(hfc.payDate), '-', year(hfc.payDate))) AS payment
  FROM hostelfeescollection hfc
  INNER JOIN hostelfeecollectmode hfm ON hfc.tranId = hfm.tranId
  INNER JOIN student_info_1 si ON si.std_code = hfc.stdCode
  WHERE hfc.tranId = 'TRAN-AZZZY69454'
) AS tab1
2
ответ дан DaveRandom 26 August 2018 в 20:17
поделиться

Увидев, что это довольно популярный вопрос - ответ ДА.

Для столбца column в таблице table, содержащего все ваши данные, разделенные комой:

CREATE TEMPORARY TABLE temp (val CHAR(255));
SET @S1 = CONCAT("INSERT INTO temp (val) VALUES ('",REPLACE((SELECT GROUP_CONCAT( DISTINCT  `column`) AS data FROM `table`), ",", "'),('"),"');");
PREPARE stmt1 FROM @s1;
EXECUTE stmt1;
SELECT DISTINCT(val) FROM temp;
< hr>

Пожалуйста, помните, однако, чтобы не хранить CSV в вашей БД


Per @Mark Amery - так как это переводит значения, разделенные комой, в инструкцию INSERT, будьте осторожны при запуске ее на неанитированной data


Просто повторите, пожалуйста, не храните CSV в своей БД; эта функция предназначена для преобразования CSV в разумную структуру БД и не использоваться в любом месте вашего кода. Если вам нужно использовать его в производстве, переосмыслите структуру своего БД

22
ответ дан eithed 26 August 2018 в 20:17
поделиться
  • 1
    У меня есть ужасный столбец, содержащий данные, разделенные каналами (вместо запятых), но комбинация скобок, которую вы использовали, и факт, что запятые заменяются, сделала эту вторую строку настолько сложной для разбивки, что я не могу ее переписать для труб вместо замены запятой. – BadHorsie 18 May 2016 в 12:31
  • 2
    @BadHorsie - SET @S1 = CONCAT("INSERT INTO temp (val) VALUES ('",REPLACE((SELECT GROUP_CONCAT( DISTINCT `column`) AS data FROM `table`), "|", "'),('"),"');"); – eithed 18 May 2016 в 13:55
  • 3
    Спасибо, мне удалось. Это легче увидеть в подсветке синтаксиса Stackoverflow. phpMyAdmin не очень хорошо выделяет синтаксис. – BadHorsie 18 May 2016 в 16:26
  • 4
    -1; хороший лорд, что это за безумие? Это не удастся, если значения в table содержат кавычки, возможно, подвергая вас инъекциям SQL. – Mark Amery 1 April 2017 в 18:40
  • 5
    Хорошая точка @MarkAmery - добавление отказа от ответственности! – eithed 3 April 2017 в 08:16

Вот как вы это делаете для 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, чтобы найти право, слово, позицию.

-1
ответ дан Eugene Yokota 26 August 2018 в 20:17
поделиться

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

    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;
-1
ответ дан Jonathan 26 August 2018 в 20:17
поделиться

Вы можете создать для этого функцию:

/**
* Split a string by string (Similar to the php function explode())
*
* @param VARCHAR(12) delim The boundary string (delimiter).
* @param VARCHAR(255) str The input string.
* @param INT pos The index of the string to return
* @return VARCHAR(255) The (pos)th substring
* @return VARCHAR(255) Returns the [pos]th string created by splitting the str parameter on boundaries formed by the delimiter.
* @{@example
*     SELECT SPLIT_STRING('|', 'one|two|three|four', 1);
*     This query
* }
*/
DROP FUNCTION IF EXISTS SPLIT_STRING;
CREATE FUNCTION SPLIT_STRING(delim VARCHAR(12), str VARCHAR(255), pos INT)
RETURNS VARCHAR(255) DETERMINISTIC
RETURN
    REPLACE(
        SUBSTRING(
            SUBSTRING_INDEX(str, delim, pos),
            LENGTH(SUBSTRING_INDEX(str, delim, pos-1)) + 1
        ),
        delim, ''
    );

Преобразование магического псевдокода для его использования: у вас есть:

SELECT e.`studentId`, SPLIT_STRING(',', c.`courseNames`, e.`courseId`)
FROM...
12
ответ дан Josias Iquabius 26 August 2018 в 20:17
поделиться
  • 1
    Имейте в виду, что приведенный выше код не будет работать для многобайтовых символов, таких как UTF-8. Я думаю, что использование CHAR_LENGTH вместо LENGTH должно сделать трюк. – Lieuwe 13 September 2016 в 08:42

До сих пор я хотел сохранить эти разделенные запятыми списки в своем SQL-db - хорошо осведомленный обо всех предупреждениях!

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

  • Использование поисковых таблиц НЕ вызывает больше кода, чем эти уродливые строковые операции при использовании значений, разделенных запятыми, в одном поле.
  • Таблица поиска позволяет создавать собственные числовые форматы и, следовательно, НЕ больше, чем эти поля csv. Хотя это SMALLER.
  • Привязанные строковые операции тонкие в языке высокого уровня (SQL и PHP), но дорогостоящие по сравнению с использованием массивов целых чисел.
  • Базы данных не предназначены для быть правдоподобным, и в основном глупо пытаться придерживаться структур из-за их удобочитаемости / прямой редактируемости, как и я.

Короче говоря, есть причина, по которой нет родной SPLIT () в MySQL.

30
ответ дан JYelton 26 August 2018 в 20:17
поделиться
  • 1
    Я использую это, когда пользователь фильтрует ввод данных, сделанный им самим. т.е. когда у вас есть открытый вопрос, например «принятые расширения», то пользователю необходимо отфильтровать критерии. Чтобы сохранить связанные данные, лучше всего, как вы сказали, использовать отдельную связанную таблицу – Alwin Kesler 30 October 2014 в 14:25
  • 2
    нет способа передать массив в хранимую процедуру mysql ... так что я делаю сейчас, если нет способа передать текст и разбить в рутине ?! ( – Serge 13 August 2015 в 16:33
  • 3
    Да, хорошо, , однако : my цель в том, что вы хотите дезагрегировать SPLIT (), - это нормализовать данные, которые в настоящее время не нормализованы, так что я могу сохранить их в нормализованный формат в будущем! Если ваш комментарий верен, то нехватка этой функции MySQL препятствует моему прогрессу в нормализации моих данных! Это очень странно и асимметрично, если MySQL предоставляет функцию GROUP_CONCAT () , но не соответствующую функцию обратного: SPLIT ()! Похоже, мне нужно будет «решить» решение ». вместе с SUBSTRING_INDEX () вместо этого! – Matthew Slyman 26 January 2016 в 11:30
  • 4
    Прочтите этот набор функций MySQL как: Если ваши данные находятся в базе, уже слишком поздно. Позаботьтесь о нормализации по дизайну / перед / вставкой. Нормализация в / чтение / данные не является нашей задачей. Опять же, это то, что я узнал из этого. – Melchior Blausand 8 February 2016 в 17:58
  • 5
    «почему в MySQL нет встроенной функции SPLIT () Я ожидаю ответа, потому что функции возвращают одно значение. И Split () по определению возвращает несколько значений (традиционно массив). Возможно, хранимая процедура? Но тогда вам нужно что-то сделать с выходом ... – Matt C 13 June 2017 в 03:34

Можно взорвать строку в инструкции MySQL SELECT.

Сначала сгенерируйте ряд чисел с наибольшим количеством разграниченных значений, которые вы хотите взорвать. Либо из таблицы целых чисел, либо путем объединения чисел вместе. Следующее генерирует 100 строк, давая значения от 1 до 100. Его можно легко расширить, чтобы получить большие диапазоны (добавьте еще один дополнительный запрос, дающий значения от 0 до 9 для сотен - отсюда давая от 0 до 999 и т. Д.).

SELECT 1 + units.i + tens.i * 10 AS aNum
FROM (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens

Это может быть крест, соединенный с вашей таблицей, чтобы дать вам значения. Обратите внимание, что вы используете SUBSTRING_INDEX, чтобы получить значение с разделителем до определенного значения, а затем используйте SUBSTRING_INDEX для получения этого значения, за исключением предыдущих.

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(clients.courseNames, ',', sub0.aNum), ',', -1) AS a_course_name
FROM clients
CROSS JOIN
(
    SELECT 1 + units.i + tens.i * 10 AS aNum, units.i + tens.i * 10 AS aSubscript
    FROM (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
    CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
) sub0

Как вы можете видеть, здесь есть небольшая проблема, последнее разделимое значение повторяется много раз. Чтобы избавиться от этого, вам нужно ограничить диапазон чисел в зависимости от количества разделителей. Это можно сделать, взяв длину поля с разделителями и сравнивая его с длиной поля с разделителями, когда разделители изменены на «» (чтобы удалить их). Из этого вы можете получить количество разделителей: -

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(clients.courseNames, ',', sub0.aNum), ',', -1) AS a_course_name
FROM clients
INNER JOIN
(
    SELECT 1 + units.i + tens.i * 10 AS aNum
    FROM (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
    CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
) sub0
ON (1 + LENGTH(clients.courseNames) - LENGTH(REPLACE(clients.courseNames, ',', ''))) >= sub0.aNum

В исходном поле примера вы могли (например) подсчитать количество студентов на каждом курсе на основе этого. Обратите внимание, что я изменил sub-запрос, который получает диапазон чисел, чтобы вернуть 2 числа, 1 используется для определения имени курса (поскольку они основаны на старте на 1), а другой получает индекс (поскольку они основаны на запуске на 0).

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(clients.courseNames, ',', sub0.aNum), ',', -1) AS a_course_name, COUNT(clientenrols.studentId)
FROM clients
INNER JOIN
(
    SELECT 1 + units.i + tens.i * 10 AS aNum, units.i + tens.i * 10 AS aSubscript
    FROM (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
    CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
) sub0
ON (1 + LENGTH(clients.courseNames) - LENGTH(REPLACE(clients.courseNames, ',', ''))) >= sub0.aNum
LEFT OUTER JOIN clientenrols
ON clientenrols.courseId = sub0.aSubscript
GROUP BY a_course_name

Как вы можете видеть, это возможно, но довольно грязно. И с небольшой возможностью использовать индексы он не будет эффективным. Далее диапазон должен справляться с наибольшим количеством разделимых значений и работает, исключая множество дубликатов; если максимальное количество разделимых значений очень велико, это значительно замедлит работу. В целом, как правило, гораздо лучше правильно нормализовать базу данных.

3
ответ дан Kickstart 26 August 2018 в 20:17
поделиться

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

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

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

Таблица 3: clientid, courseid

Затем выполните JOIN, и вы отправитесь на гонки.

2
ответ дан Kurt 26 August 2018 в 20:17
поделиться
  • 1
    да, теперь я мучительно осознаю, насколько плохое решение было идти с разделенным запятыми списком. – nickf 23 January 2009 в 06:03
  • 2
    никогда не поздно перепроектировать :-) – Adam 23 January 2009 в 06:23
  • 3
    @Adam, астронавты не согласны – Parris Varney 25 August 2011 в 17:34

Я использовал вышеупомянутую логику, но немного изменил ее. Мой вход имеет формат: «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;
1
ответ дан pinkgothic 26 August 2018 в 20:17
поделиться

Если вам нужно получить таблицу из строки с разделителями:

SET @str = 'function1;function2;function3;function4;aaa;bbbb;nnnnn';
SET @delimeter = ';';
SET @sql_statement = CONCAT('SELECT '''
                ,REPLACE(@str, @delimeter, ''' UNION ALL SELECT ''')
                ,'''');
SELECT @sql_statement;
SELECT 'function1' UNION ALL SELECT 'function2' UNION ALL SELECT 'function3' UNION ALL SELECT 'function4' UNION ALL SELECT 'aaa' UNION ALL SELECT 'bbbb' UNION ALL SELECT 'nnnnn'
2
ответ дан user1894169 26 August 2018 в 20:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: