Можно ли это сделать в запросе MySQL, или это нужно сделать в PHP? (Серверный)

58
6

У меня есть таблица:

id
first
last
institution
address
space1_1_value
space1_2_value
space2_1_value
space2_2_value
space3_1_value
space3_2_value
agreement

(Это сокращает количество полей, например, ради).

Сначала мне нужно было разбить каждую группировку "space x" (т.е. space1.x, space2.x, space3.x) на свои собственные ROWS (хотя все данные были в 1 записи/строке)

id | первая | последняя | учреждения | адрес | space1_1_value | space1_2_value | соглашение

Если в space2_1_value есть значение, тогда:

id | первая | последняя | учреждения | адрес | space2_1_value | space2_2_value | соглашение

Если в space3_1_value есть значение, то:

id | первая | последняя | учреждения | адрес | space3_1_value | space3_2_value | соглашение

Это было разработано с использованием следующего запроса:

SELECT first, last, space1_1_value as space_value FROM report
UNION ALL
SELECT first, last, space2_2_value as space_value FROM report WHERE space2_2_value <> ''
UNION ALL
SELECT first, last, space3_3_value as space_value FROM report WHERE space3_3_value <> ''
ORDER BY first

Однако мне было поручено разбить это еще дальше, но я не уверен, возможно ли это с запросом или, если это действительно нужно сделать на стороне бэкэнда /PHP?

Поэтому соблюдайте приведенную выше директиву (что является требованием):

Поэтому для каждой группы SPACE1.x есть столбец с запятыми значениями в нем.

Для этого мы будем говорить, что все space1_2_value, space2_2_value & space3_3_value cols содержат что-то вроде:

March 3,March 5,March 6
March 1,March 2
Feb 27

например.

Таким образом, каждый столбец может иметь от 1 до многих значений с разделителями-запятыми.

Есть ли способ в MySQL разбить эти значения и вернуть строку зеркалирования для каждого из них? Или что-то, что необходимо сделать на стороне бэкэнда (PHP)?

Я дал несколько минут, чтобы попытаться подумать, как бы я сделал это на PHP.

Но я получаю пойманные циклы foreach() без индекса? (или просто простой для() цикл WITH с индексом, но не много накладных расходов, чтобы проверить, пусто ли каждое значение $ (вручную).

спросил(а) 2017-07-24T23:44:00+03:00 3 года, 3 месяца назад
1
Решение
58

Это можно сделать в sql. Одним из способов было бы использовать "вспомогательную таблицу" с целыми числами, которые вы можете join своим данным, чтобы получить свою строку несколько раз, а затем извлечь только элемент n -th.

Попробуй это:

-- helper table with a listof integers from 1 to 10
create table _int_1_10 (id int primary key);
insert into _int_1_10 (id)
values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);

-- some example data
create table test_strexplode (
id int primary key,
space_value_1 varchar(200),
space_value_2 varchar(200)
);

insert into test_strexplode (id, space_value_1, space_value_2)
values (1, 'row 1', 'March 3,March 5,March 6 March 1,March 2 Feb 27'),
(2, 'row 2', 'March 3,,March 5'),
(3, 'row 3', '');

select space_value_1,
_int_1_10.id,
-- extracts the "_int_1_10.id"th element
SUBSTRING_INDEX(SUBSTRING_INDEX(
space_value_2,',',_int_1_10.id),',',-1) as subentry
from test_strexplode
join _int_1_10
on _int_1_10.id <=
-- number of elements in your string (= number of "," + 1)
char_length(space_value_2) - char_length(replace(space_value_2, ',', '')) + 1
order by test_strexplode.id, _int_1_10.id;

Это даст вам:

+---------------+----+-----------------+
| space_value_1 | id | subentry |
+---------------+----+-----------------+
| row 1 | 1 | March 3 |
| row 1 | 2 | March 5 |
| row 1 | 3 | March 6 March 1 |
| row 1 | 4 | March 2 Feb 27 |
| row 2 | 1 | March 3 |
| row 2 | 2 | |
| row 2 | 3 | March 5 |
| row 3 | 1 | |
+---------------+----+-----------------+

Я использовал ваши данные примера, которые отсутствуют , и поэтому результат содержит, например, March 2 Feb 27. Также обратите внимание, что некоторые субтитры пусты (поскольку мои выборочные данные содержат пустые записи); вы можете или не хотите отфильтровывать их. Ваше число таблица будет, очевидно, должны содержать цифры по крайней мере, до максимального числа элементов, которые вы ожидаете, чтобы иметь в любом из строк (и, если он содержит 0 или отрицательные числа, фильтровать их в on -clause).

substring_index(str,delim,count) возвращает подстроку из строки str перед count delim разделителя delim. Полный оператор для subentry будет для положительного числа возвращать либо _int_1_10.id -th, либо, если строка имеет меньше элементов, последний элемент.

on -clause, таким образом, вычисляет количество элементов (путем подсчета числа ,), чтобы предотвратить получение последнего элемента в несколько раз. Если ваша строка не содержит пустых элементов (например , в моих образцовых данных), вам не нужна эта часть, но она может добавить пустой элемент, чтобы пометить конец списка.

Вы можете применить этот код ко всему набору результатов, например, используя

...
from (select ...
space1_1_value as space_value_1,
space1_2_value as space_value_2
...
union all ... union all ... ) as test_strexplode
join _int_1_10 ...

Он будет работать, но он может быть медленным. Он не может использовать индекс в space*_2_value -columns и должен будет выполнить много стыков и строковой оценки. Однако вы не можете много сделать, кроме нормализации своих данных.

Если это полезно сделать в sql, вероятно, будет зависеть от того, что вы делаете с данными. Если вы просто собираетесь отображать его в html-таблице на веб-странице, возможно, проще и быстрее просто пропустить массив в php. Чтобы сортировать, фильтровать или join вашему набору результатов, его, вероятно, намного проще реализовать (и, скорее всего, быстрее) в sql, возможно, даже если вы используете его в рамках. Если вы собираетесь обновлять значения, это будет намного проще делать в php, так как это, скорее всего, будет беспорядок в sql (на этом наборе результатов).

ответил(а) 2017-07-25T15:39:00+03:00 3 года, 3 месяца назад
41

Отправленный ответ от имени ОП.

Я закатил свое собственное решение для PHP (но спасибо @Solarflare для SQL-решения).

PHP: (очевидно, используя UNION ALL QUERY... и т.д.)

$getRequests_stmt = $conn->prepare($getRequests_sql);
$getRequests_stmt->execute();
$getRequests_stmt->setFetchMode(PDO::FETCH_ASSOC);
$results = $getRequests_stmt->fetch(PDO::FETCH_ASSOC);
$colcount = $getRequests_stmt->columnCount();
$rowcount = $getRequests_stmt->rowCount();
$date = new DateTime();
$currdate = "Results as of: ".$date->format('m-d-Y H:i:s');
$namedate = $date->format('m-d-Y-H_i_s');
//Get Headers
for ($i = 0; $i < $colcount; $i++) {
$col = $getRequests_stmt->getColumnMeta($i);
$colname = $col['name'];
$header .= $colname . "\t";
}

//Get Row Data
while ($results = $getRequests_stmt->fetch()){
$line = '';
foreach($results as $key => $value) {
if ((!isset($value)) || ($value == '')) {
$value = "\t";
} else {
$value = str_replace('"', '""', $value);
$value = '"' . $value . '"' . "\t";
}
$line .= $value;
}
$data .= trim($line) . "\n";
}

//Data check
$data = str_replace("\r", '', $data);
if ($data == '') {
$data = "\n(0) space requests found\n";
}

//Export spreadsheet...

ответил(а) 2017-07-26T23:40:00+03:00 3 года, 3 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема