What is the correct syntax for a Regex find-and-replace using REGEXP_REPLACE in MariaDB? - mysql

I need to run a regex find-and-replace against a column named message in a MySQL table named post.
My database is running MariaDB 10.
According to the docs, MariaDB 10 has a new REGEXP_REPLACE function designed to do exactly this, but I can't seem to figure out the actual syntax.
It will affect 280,000 rows, so ideally there's also a way to limit it to only changing one specific row at a time while I'm testing it, or simply doing a SELECT rather than an UPDATE until I'm sure it does what I want.
The regex I want to run:
\[quote\sauthor=(.+)\slink=[^\]]+]
The replacement string:
[quote="$1"]
The following was what I tried, but it just throws a SQL error:
UPDATE post SET message = REGEXP_REPLACE(message, '\[quote\sauthor=(.+)\slink=[^\]]+]', '[quote="$1"]') WHERE post_id = 12
In this case, the original message was:
[quote author=Jon_doe link=board=2;threadid=125;start=40#msg1206 date=1065088] and the end result should be [quote="Jon_doe"]
What is the proper syntax to make this REGEXP_REPLACE work?

You have to do a lot of escaping here:
REGEXP_REPLACE(message, "\\[quote\\sauthor=(.+)\\slink=[^\\]]+]", "\\[quote=\"\\1\"\\]")
Please note that you have to reference the Group by \\1

Related

Correct MariaDB Syntax for SQL Replace Statement

After trying to determine why my SQL statement was returning an error in the Node code I am refactoring to connect to MariaDB rather than via SQL Anywhere, I have narrowed it down to the REPLACE statement we use to compute how many records to process, and how many to skip.
My initial test SQL SELECT statement looks like this:
SELECT customer_name FROM ar.customers
We then use a REPLACE statement to, as I say, determine how many records to process, and how many to skip. When we were using SQL Anywhere that looked like this:
const sql = this.query.replace(/SELECT/i, `SELECT TOP ${recordsPerRun} START AT ${recordsProcessed + 1}`);
That syntax needs to change because MariaDB uses "LIMIT" instead of "TOP". And from my understanding, the first parameter will be the number of records to skip, and the second one how many to return.
So, in my case, it'd be something like:
LIMIT ${recordsProcessed}, ${recordsPerRun}
However, I can't quite get the full syntax right. How can I write this REPLACE statement in a way that will work with my initial test SQL SELECT statement from above? This seems tricky to do since in MariaDB LIMIT now goes at the end of the query, not at the beginning, like TOP did for MySQL.
LIMIT goes at the end, so there's nothing to replace, just concatenate it:
const sql = this.query + ` LIMIT ${recordsProcessed}, ${recordsPerRun}`;
or combine it into the template:
const sql = `${this.query} LIMIT ${recordsProcessed}, ${recordsPerRun}`;

Is there an equivalent way to do MySQL's JSONOBJECTAGG() in MariaDB?

The server I was working on for a data project crashed and I am now recreating the database. I used to be working on a MySQL database, and now I'm using MariaDB. I have never used MariaDB before.
Previously, I used the following command to insert some data into one table from another:
CREATE TABLE collaborators_list
SELECT awards.id, awards.researcher_name, awards.organization_id,
JSON_OBJECTAGG(awards.fiscal_year, coapplicants.coapplicant_name,
coapplicants.organization_number)
AS 'coapplicants_list' FROM awards
INNER JOIN coapplicants
ON awards.id=coapplicants.id
GROUP BY awards.researcher_name, awards.organization_id;
Basically, I want to do the same thing in MariaDB. I tried looking here:
https://mariadb.com/kb/en/library/json-functions/
but unless I am misreading something, none of these is what I really want...
Help!
No, MariaDB still does not support JSON_ARRAYAGG and JSON_OBJECTAGG functions. A JIRA ticket has been raised for requesting this feature: https://jira.mariadb.org/browse/MDEV-16620
Now, from the docs of JSON_OBJECTAGG():
It takes only two column names or expressions as arguments, the
first of these being used as a key and the second as a value.
An error occurs if any key name is NULL or the number of arguments is
not equal to 2.
However, you are specifying three arguments in JSON_OBJECTAGG(awards.fiscal_year, coapplicants.coapplicant_name, coapplicants.organization_number); so your attempted query will not work as well.
Now, in the absence of the required functions, we can utilize Group_Concat() with Concat(). I am assuming that you need only first two arguments (as explained in previous para).
GROUP_CONCAT( DISTINCT CONCAT('"', awards.fiscal_year, '": "',
coapplicants.coapplicant_name, '"')
SEPARATOR ', ')
Note that, in case of string getting very very long, Group_Concat() may truncate it. So, you can increase the allowed length, by executing the following query, before the above query:
SET SESSION group_concat_max_len = ##max_allowed_packet;

MySQL REPLACE in UPDATE does not work properly

The following query:
select replace(`Abilities`, 'export_import', 'auto') from fl_account_types;
gives me 'auto,listings' correct replacement from Abilities column. However, when I execute:
update fl_account_types set `Abilities` = replace(`Abilities`, 'export_import', 'autos');
MySQL just omits 'export_import' string and replaces Abilities with 'listings' string.
What could be the reason?
The problem was that Abilities was of type SET and I was trying to replace with a value which was not listed in a definition of it. But I still do not understand why select replace works well and why MySQL do not throw an error.

Could this simple T-SQL update fail when running on multiple processors?

Assuming that all values of MBR_DTH_DT evaluate to a Date data type other than the value '00000000', could the following UPDATE SQL fail when running on multiple processors if the CAST were performed before the filter by racing threads?
UPDATE a
SET a.[MBR_DTH_DT] = cast(a.[MBR_DTH_DT] as date)
FROM [IPDP_MEMBER_DEMOGRAPHIC_DECBR] a
WHERE a.[MBR_DTH_DT] <> '00000000'
I am trying to find the source of the following error
Error: 2014-01-30 04:42:47.67
Code: 0xC002F210
Source: Execute csp_load_ipdp_member_demographic Execute SQL Task
Description: Executing the query "exec dbo.csp_load_ipdp_member_demographic" failed with the following error: "Conversion failed when converting date and/or time from character string.". Possible failure reasons: Problems with the query, "ResultSet" property not set correctly, parameters not set correctly, or connection not established correctly.
End Error
It could be another UPDATE or INSERT query, but the otehrs in question appear to have data that is proeprly typed from what I see,, so I am left onbly with the above.
No, it simply sounds like you have bad data in the MBR_DTH_DT column, which is VARCHAR but should be a date (once you clean out the bad data).
You can identify those rows using:
SELECT MBR_DTH_DT
FROM dbo.IPDP_MEMBER_DEMOGRAPHIC_DECBR
WHERE ISDATE(MBR_DTH_DT) = 0;
Now, you may only get rows that happen to match the where clause you're using to filter (e.g. MBR_DTH_DT = '00000000').
This has nothing to do with multiple processors, race conditions, etc. It's just that SQL Server can try to perform the cast before it applies the filter.
Randy suggests adding an additional clause, but this is not enough, because the CAST can still happen before any/all filters. You usually work around this by something like this (though it makes absolutely no sense in your case, when everything is the same column):
UPDATE dbo.IPDP_MEMBER_DEMOGRAPHIC_DECBR
SET MBR_DTH_DT = CASE
WHEN ISDATE(MBR_DTH_DT) = 1 THEN CAST(MBR_DTH_DT AS DATE)
ELSE MBR_DTH_DT END
WHERE MBR_DTH_DT <> '00000000';
(I'm not sure why in the question you're using UPDATE alias FROM table AS alias syntax; with a single-table update, this only serves to make the syntax more convoluted.)
However, in this case, this does you absolutely no good; since the target column is a string, you're just trying to convert a string to a date and back to a string again.
The real solution: stop using strings to store dates, and stop using token strings like '00000000' to denote that a date isn't available. Either use a dimension table for your dates or just live with NULL already.
Not likely. Even with multiple processors, there is no guarantee the query will processed in parallel.
Why not try something like this, assuming you're using SQL Server 2012. Even if you're not, you could write a UDF to validate a date like this.
UPDATE a
SET a.[MBR_DTH_DT] = cast(a.[MBR_DTH_DT] as date)
FROM [IPDP_MEMBER_DEMOGRAPHIC_DECBR] a
WHERE a.[MBR_DTH_DT] <> '00000000' And IsDate(MBR_DTH_DT) = 1
Most likely you have bad data are are not aware of it.
Whoops, just checked. IsDate has been available since SQL 2005. So try using it.

MySQL: CONCAT_WS function is running on local but not on server

Some days ago I asked a question about my problem and I was advised to use CONCAT_WS function. I am using CONCAT_WS on my local mysql database and it is working perfectly. But it is not working on server(application hosted) and generate the following error.
FUNCTION test.CONCAT_WS does not exist
Here test in error string is my database name on server.
My query is like this:
SELECT * FROM patient WHERE CONCAT_WS (',', LastName,FirstName,BirthDate ) NOT IN ('Abdul,Quddus,2000-09-30','Wasim,Akram,1993-09-12');
Can someone tell me the problem or suggest me another solution asked in linked question above ?
Thanks
The easiest way to fix it is by removing the whitespace between the function name and the parenthesis, i.e. CONCAT_WS(...) instead of CONCAT_WS (...).
From the MySQL Manual:
By default, there must be no
whitespace between a function name and
the parenthesis following it. This
helps the MySQL parser distinguish
between function calls and references
to tables or columns that happen to
have the same name as a function.
...
You can tell the MySQL server to
accept spaces after function names by
starting it with the
--sql-mode=IGNORE_SPACE option.
Also, this behavior depends on the MySQL version, this is why it works on one server and doesn't work on another, quote from the "Function Name Parsing and Resolution" manual page:
The number of function names affected
by IGNORE_SPACE was reduced
significantly in MySQL 5.1.13, from
about 200 to about 30.