How to do mysql SELECT json - mysql

Is there a way to select json within mysql? Or do I need to use concatenation to build it? I need to do a large json update statement and I'd rather do it within the db so I don't have to iterate of tens of millions of rows. Is there a better approach than:
SELECT CONCAT('{"field1: "', field1, '"}') FROM mytable

mysql Server (since Version 8.0): SELECT [field with json blob]->>"$.json_field" FROM mytable; see
mariaDB Server (since Version 10.26) SELECT JSON_EXTRACT([field with json blob], "$.json_field") from mytable see

Related

MySQL temporary variable in table name

I have a series of tables with the same prefix, and I need to select data from the latest version --whose postfix with the highest numeric number. Here is what I have:
SELECT
#latest_version_number :=
MAX(
CAST(SUBSTRING_INDEX(table_name,'_',-1) AS UNSIGNED)
)
FROM information_schema.tables
WHERE lower(table_name) like '{table_prefix}%';
SELECT
*
FROM CONCAT('`{table_prefix}', CAST(#latest_version_number AS CHAR), '`')
It behaved like what I expected when ran as 2 separate queries in the console. But I got "syntax error" trying to run it as a single query. What's the cleanest way to refactor this into a single query? Thanks
The only way I'm aware that you can use a variable in a table name in MySQL is using the prepare + execute statements.
Here is an example I found online that gives you exact instructions.
https://www.tutorialspoint.com/set-user-defined-variable-with-table-name-in-mysql-prepare-statement

How to pass the results of a local MSSQL query into the query string for a linked MySQL database

Background:
I am working on a project which generates documents based on the contents of a remote MySQL (v8) database . To accomplish this, the program uses a local MSSQL (2017) database with a link to the remote MySQL db.
Issue:
I need to update the MySQL database based the contents of a query from the MSSQL as follows:
EXEC('UPDATE LinkedMySQLDB.TableToUpdate AS a SET a.MySQLField=''updated'' WHERE a.ID IN (LocalMSSQLDB.LocalTable.ID) ;') AT LinkedMySQLServer
However, every time I try this it throws an error at:
(LocalMSSQLDB.LocalTable.ID)
Question:
Is there a way to pass the results of a local query into the query string for the remote database?
Or, is there a different approach that is recommended?
Thanks in advance.
You are trying to access the values of LocalMSSQLDB.LocalTable.ID on MySQL server. That is not possible.
You could use a variable to calculate the statement.
In the example below I use some other names for the databases and fields. But you should get the general idea. By using concat I combine text parts with the result of the subqueries converted to a comma separated list using STRING_AGG.
declare #strSQL varchar(200);
select #strSQL=concat('UPDATE test.test set text=''updated'' WHERE ID in (',(SELECT STRING_AGG(ID, N', ') FROM [SQLTest].dbo.tblTest),');');
EXEC(#strSQL) AT MYSQL2;
This part (SELECT STRING_AGG(ID, N', ') FROM [SQLTest].dbo.tblTest) returns a string. If the local table contains the ID's 1 and 2, the result will be 1, 2. Concatenated with 'UPDATE test.test set text=''updated'' WHERE ID in (' and ');' the final result will be:
UPDATE test.test set text='updated' WHERE ID in (1, 2);
When this is send to the MySQL server named MYSQL2, you get the desired result.
On your servers it would be something like:
declare #strSQL varchar(200);
select #strSQL=concat('LinkedMySQLDB.TableToUpdate AS a SET a.MySQLField=''updated'' WHERE ID in (',(SELECT STRING_AGG(ID, N', ') FROM LocalMSSQLDB..LocalTable),');');
EXEC(#strSQL) AT LinkedMySQLServer;
Be sure to make room for all your id's in #strSQL. 200 characters might not be enough.

How to insert datetime into mysql from mssql with INSERT INTO OPENQUERY SELECT

I've been using the following format to insert into my mysql database previously, and would like to keep it uniform.
INSERT INTO OPENQUERY (ENET, 'SELECT * FROM ActiveDirectory.Computers') -- MYSQL database
SELECT c.[CommonName],
c.[DistinguishedName],
c.[SAMAccountName],
c.[DNSHostName],
c.[Location],
c.[Division],
c.[Department],
c.[ManagedBy],
c.[MachineRole],
CAST(CAST(c.[LastLogon] as timestamp) as datetime) AS LastLogon,
c.[OperatingSystem],
c.[OperatingSystemVersion],
c.[ServicePack],
c.[OU],
c.[CreatedOn],
c.[ChangedOn],
CASE WHEN c.[UserAccountControl] & 2 = 0 THEN 1 ELSE 0 END AS [Enabled] -- Check to see if disabled. Disabled = bitwise of 2; 4098 = 4096 + 2 = Trust Account + Disabled
FROM [IT_ActiveDirectory].[dbo].[ADComputerTable] c -- MSSQL database
My problem comes when inserting the fields that are datetimes in MSSQL (c.LastLogon, c.CreatedOn, c.ChangedOn) into mysql fields that are also datetimes. I have tried almost every combination of CAST() and CONVERT() I can think of, but I may have missed something. I have also tried changing mysql's field type to timestamp.
It returns: Conversion failed when converting date and/or time from character string.
It seems strange to me that MSSQL won't just send the data to MYSQL and let it do the conversion. Instead it looks like it is trying to convert and match the datatypes and data before it sends it to MYSQL.
If I can't insert it this way, I am open to another format, like if its possible to do the insert inside of the OPENQUERY() SELECT. Any suggestions? I'm dead in the water at the moment.
I would try to convert to ISO-8601 format string:
INSERT INTO OPENQUERY (ENET, 'SELECT * FROM ActiveDirectory.Computers')
SELECT
...,
CONVERT(VARCHAR, LastLogon, 126) AS LastLogon
FROM [IT_ActiveDirectory].[dbo].[ADComputerTable];
Also I don't like SELECT * in OPENQUERY. If columns are matched by position it is error-prone. Consider expanding start to columns.

SQL Like with double pipe concatenation

I'm having a problem with a SQL query that must match the username of a user out of a column that contains all the users usernames.
So the column will contain something like:
|USER1|USER2|USER3|USER11|USER22|
The user have pipes on the left and right to prevent "USER1" be matched even in "USER11".
My query is
SELECT * FROM myTable WHERE CONCATUSERS LIKE ('%|' || 'USER1' || '|%')
Note that the USER1 in the query is a variable generated from our code so I must keep the concatenation syntax and I must use a standard syntax too (the code will run in mySQL, SQLServer etc..
So what is the correct way of concatenating strings in a LIKE clause?
MySQL uses the double pipes for concat. SQL Server you can use +.
SELECT *
FROM myTable
WHERE CONCATUSERS LIKE ('%' + '|user1|' + '%')
Use CONCAT.
(available on SQL server 2012 and beyond)
It has the benefit that it implicitly converts types to add the value to the string. And it's not just available on Sql Server and MySql.
SELECT * FROM myTable WHERE CONCATUSERS LIKE CONCAT('%|','USER1','|%');
Do note that in MySQL the result will be NULL if one of the concatenated values is NULL. But not on Sql Server.
It's just Oracle that's being stubborn by only allowing 2 values to that function.
So if the SQL needs to run unchanged on MySQL, a recent Sql Server AND Oracle then this should work:
SELECT * FROM myTable WHERE CONCATUSERS LIKE CONCAT(CONCAT('%|','USER1'),'|%');
You can go with CONCAT function.
As it is supported in both SQL and MySQL
SELECT *
FROM xpat
WHERE plname LIKE concat('%' ,'|user1|' ,'%');

MySQL: how can i convert a string '1,2,3,4' to a (1,2,3,4) so i'll be able to use it in a 'where X in ()' statement

I ran a query that resulted in the string '1,2,3,4'.
How can I run a second query that treats that string as a list of numbers. So I'll be able to do:
select * from tbl where name not in (1,2,3,4)
I would like an answer in pure MySQL.
Well first of all, this usually means that your database structure is not good; you should normalize your database.
However, you can do what you want, with the FIND_IN_SET function:
SELECT * FROM tbl WHERE NOT FIND_IN_SET(name, '1,2,3,4')
Use FIND_IN_SET:
select * from tbl where FIND_IN_SET(name, '1,2,3,4') = 0
Like the other answer, I would also recommend normalizing your database if at all possible. This query could be slow as it will require a scan of the table. Even if there is an index on name this query won't be able to use it efficiently.