У меня довольно большая база данных со столбцом, в котором есть строки, которые по большей части действительно просто целые числа, например «1234» или «345». Однако к некоторым из них добавлены строки (разной длины), например, «a123» или «abc123».
Есть ли умный способ создать новый столбец только с целочисленными значениями? Таким образом, «abc123» станет «123»? Я знаю, что могу читать все строки в PHP, а затем использовать регулярное выражение, чтобы сделать это довольно легко, но я хотел посмотреть, есть ли способ позволить SQL сделать это за меня.






К сожалению, вы не можете сделать это в MySQL самостоятельно. MySQL имеет возможности сопоставления регулярных выражений, но не возможности замены регулярных выражений. Лучшим вариантом было бы использовать регулярное выражение в PHP для выполнения вашей замены. (Source)
$sql = "SELECT `id`, `myMixedColumn` FROM `myTable` "
. "WHERE `myMixedColumn` NOT RLIKE '^[[:digit:]]+$'";
$r = mysql_query($sql);
$updates = array();
while ($row = mysql_fetch_assoc($r)) {
$updates = sprintf("UPDATE `myTable` SET `myIntField` = %s WHERE `id` = %d",
preg_replace("@\\D@", "", $row['myMixedColumn']),
$row['id']
);
}
Если вы действительно хотите сделать это в SQL, просто ради того, чтобы не делать этого в PHP, вы можете создать небольшую функцию, которая будет делать это, пока MySQL не реализует замену регулярного выражения, но я бы не стал ничего ставить на производительность.
Что-то подобное могло бы работать, только если бы буквы были в начале и не было бы никаких других символов, кроме [a-zA-Z]. И вам нужно будет проверить, как он работает в разных кодировках.
CREATE FUNCTION last_letter(s VARCHAR(100)) RETURNS INT
BEGIN
DECLARE last, current INT default 0;
DECLARE letter_a INT;
DECLARE letter_z INT;
DECLARE letter_iter INT;
SELECT ord('a') INTO letter_a;
SELECT ord('z') INTO letter_z;
SET letter_iter = letter_a;
# Will loop for all letters a to z
WHILE letter_iter <= letter_z DO
# Will get the last case-insensitive occurrence of a letter
SELECT LOCATE(CHAR(letter_iter), REVERSE(LOWER(s))) INTO current;
IF current > 0 THEN
SELECT LENGTH(s) - current + 1 INTO current;
END IF;
# Was that the rightmost letter?
IF current > last THEN
SET last = current;
END IF;
SET letter_iter = letter_iter + 1;
END WHILE;
# Return the max we found
RETURN last;
END; //
А затем получить целочисленные значения:
UPDATE test_table SET int_result =
CAST(SUBSTR(str_value, last_letter(str_value) + 1) AS SIGNED);
Да, как сказал nickf и как было сказано ранее, с PHP у вас может быть больше скорости и гибкости. Хотя, как вы уже знали, с PHP было бы легко, и хотели знать, сможете ли вы сделать это с помощью SQL, вот ваш ответ! :)
ой! Престижность за то, что разобрался в этом, но крик ... сделай это на php!