SQL get value from key in dictionary - mysql

I have a column in my database which is called user_log. It basically logs everything a user does on the page. I use MySQL.
It looks like that:
user_id
user_log
1028
{ "last_login":"2022-04-08 12:03:05", "blog_entry_at":"2022-04-08 12:43:12" }
Now, I want to extract all "last_login" and get the value of it.
It is a text field, but not a dict or something else

You can use json_extract in MySQL.
SELECT user_id, json_extract(user_log, '$.last_login') as last_login FROM users;
Sample query: https://onecompiler.com/mysql/3y8a3brhr
More on json_extract here in the mariadb docs: https://mariadb.com/kb/en/json_extract/

You can simply use JSON_VALUE() function provided that the DB is of version 8.0.21+ such as
SELECT JSON_VALUE(user_log, '$.last_login') AS extracted_value
FROM t

Related

how to include hard-coded value to output from mysql query?

I've created a MySQL sproc which returns 3 separate result sets. I'm implementing the npm mysql package downstream to exec the sproc and get a result structured in json with the 3 result sets. I need the ability to filter the json result sets that are returned based on some type of indicator in each result set. For example, if I wanted to get the result set from the json response which deals specifically with Suppliers then I could use some type of js filter similar to this:
var supplierResultSet = mySqlJsonResults.filter(x => x.ResultType === 'SupplierResults');
I think SQL Server provides the ability to include a hard-coded column value in a SQL result set like this:
select
'SupplierResults',
*
from
supplier
However, this approach appears to be invalid in MySQL b/c MySQL Workbench is telling me that the sproc syntax is invalid and won't let me save the changes. Do you know if something like what I'm trying to achieve is possible in MySQL and if not then can you recommend alternative approaches that would help me achieve my ultimate goal of including some type of fixed indicator in each result set to provide a handle for downstream filtering of the json response?
If I followed you correctly, you just need to prefix * with the table name or alias:
select 'SupplierResults' hardcoded, s.* from supplier s
As far as I know, this is the SQL Standard. select * is valid only when no other expression is added in the selec clause; SQL Server is lax about this, but most other databases follow the standard.
It is also a good idea to assign a name to the column that contains the hardcoded value (I named it hardcoded in the above query).
In MySQL you can simply put the * first:
SELECT *, 'SupplierResults'
FROM supplier
Demo on dbfiddle
To be more specific, in your case, in your query you would need to do this
select
'SupplierResults',
supplier.* -- <-- this
from
supplier
Try this
create table a (f1 int);
insert into a values (1);
select 'xxx', f1, a.* from a;
Basically, if there are other fields in select, prefix '*' with table name or alias

How to execute a MySQL function in a Knex query?

I have a BINARY field in my table which I usually grab like this:
SELECT HEX(users.id) AS id FROM users WHERE username = ?
I recently started using Knex because I need to be able to dynamically generate WHERE clauses from objects. Here's what I tried:
knex('users').select('HEX(users.id) AS id)').where(filter);
Here's the query it generates:
select `HEX(users`.`id)` as `id` ....
And then I tried this:
knex('users').select('HEX(`users`.`id`) AS id').where(filter);
And it comes up with this:
select `HEX(``users```.```id``)` as `id` ....
How do I execute HEX() without it being mistaken for a column name?
With knex letting to do quoting of identifiers it would look like this:
knex('users').select(knex.raw('HEX(??) AS id', ['users.id'])).where(filter);
I've found a solution. I have to use raw() function. So my query builder will look like this:
knex('users').select(knex.raw('HEX(`users`.`id`) AS id')).where(filter);

MySql explode/in_array functionalilty

In my table I have a field with data such as 1,61,34, and I need to see if a variable is in that.
So far I have this
SELECT id, name FROM siv_forms WHERE LOCATE(TheVariable, siteIds) > 0
Which works, with the exception that if the siteIds were 2,61,53, and TheVariable was 1, it would return the row as there is a 1 in 61. Is there anyway around this using native MySql, or would I need to just loop the results in PHP and filter the siteIds that way?
I've looked through the list of string functions in MySql and can't see anything that would do what I'm after.
Try with find_in_set function.
SELECT id, name FROM siv_forms WHERE find_in_set(TheVariable, siteIds);
Check Manual for find_in_set function.

Select query returns false result

eg:
Table : user
column : user_id (type is int)
SELECT * FROM user WHERE user_id = '10xyz'
is giving same result of
SELECT * FROM user WHERE user_id = '10'
The input value is not integer but not giving an error in this case.
The reason why you are getting the same result is because MySQL automatically removes the trailing characters from the string and implicitly converts it to integer.
SQLFiddle Demo
SQLFiddle Demo (updated)
If you don't want to change all your code, but you have your database queries all going through one or a few subs, you can change those to check for warnings after using a statement handle (e.g. if ( $sth->{mysql_warning_count} ) ...).
Or you can create a DBI subclass that does that automatically for you, promoting warnings to errors. If you do, many others have use for such a thing. There are configuration settings to give an error instead of a warning when updating or inserting something like '10xyz' into an integer field, but not anything broader than that, and dear Oracle considers it Not a Bug. Maybe MariaDB does (or could do) better?
datatype of user_id is in database is INT
that why it giving same output and not error

Unserialize through query at database level itself

I have a column value stored in the database as:
a:2:{i:0;s:2:"US";i:1;s:2:"19";}
I want to unserialize it during the mysql query rather than using the php unserialize function after fetching the data.
I want to do it this way so I can join another table with the serialized value. This would avoid executing a separate query after unserializing it with php, just for the joined data.
MySQL doesn't know what a PHP serialization is. You can't do it.
You can use SUBSTRING_INDEX
For example, if you have a record like this:
a:5:{s:9:"invoiceid";s:1:"8";s:8:"balance";i:5;s:14:"broughtforward";i:3;s:6:"userid";s:5:"13908";s:10:"customerid";s:1:"3";}
You can use the below SELECT statement:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',1),':',-1) AS fieldname1,
SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',2),':',-1) AS fieldvalue1,
SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',3),':',-1) AS fieldname2,
SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',4),':',-1) AS fieldvalue2,
SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',5),':',-1) AS fieldname3,
SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',6),':',-1) AS fieldvalue3,
SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',7),':',-1) AS fieldname4,
SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',8),':',-1) AS fieldvalue4,
SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',9),':',-1) AS fieldname5,
SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',10),':',-1) AS fieldvalue5
FROM table;
Check this for reference: How to unserialize data using mysql without using php
How about this? This is a MySQL user-defined function with embedded php:
CREATE FUNCTION unserialize_php RETURNS STRING SONAME 'unserialize_php.so';
Usage example:
SELECT unserialize_php('O:8:"stdClass":2:{s:1:"a";s:4:"aaaa";s:1:"b";s:4:"bbbb";}', "$obj->a")
AS 'unserialized';
+--------------+
| unserialized |
+--------------+
| aaaa |
+--------------+
1 row in set (0.00 sec)
drop function unserialize_php;
Source: https://github.com/junamai2000/mysql_unserialize_php
You can create a MySQL user-defined function and call zend_eval_string inside of the function so that you can bring back PHP variables to a MySQL result. I implemented a sample program. You can try it.
From http://www.blastar.biz/2013/11/28/how-to-use-mysql-to-search-in-php-serialized-fields/
Standard array
SELECT * FROM table WHERE your_field_here REGEXP '.*;s:[0-9]+:"your_value_here".*'
Associative array
SELECT * FROM table WHERE your_field_here REGEXP '.*"array_key_here";s [0-9]+:"your_value_here".*'
It's a very bad practice to add programming language dependent structures to database. If you do so, you always have to rely on that language.
The best approach is to have normalized table structure (different fields or tables).
The next approach is to save data as a delimited string (e.g.: 0,US,1,19). Then you can use MySQL's SUBSTRING() or to use standard serialization mechanisms like JSON encode.
As mentioned by kchteam, MySQLToolBox library comes handy for this purpose using a custom defined MySQL function getPhpSerializedArrayValueByKey available here https://github.com/KredytyChwilowki/MySQLToolBox/blob/master/getPhpSerializedArrayValueByKey.sql.
After adding this function, you can retrieve any value in the serialized array by using the following syntax,
SELECT getPhpSerializedArrayValueByKey(column_name, 'array_key') AS deseializedArrayValue FROM table_name
The given array can be unserialized like,
SELECT getPhpSerializedArrayValueByKey('a:2:{i:0;s:2:"US";i:1;s:2:"19";}
', 'key_to_retrieve') AS key_to_retrieve
For serialized arrays You can use function getPhpSerializedArrayValueByKey from here
You can join your table simply in this way
SELECT
table_to_join.ID as table_to_join_ID ,
serialized_table.ID AS serialized_table_ID,
FROM
table_to_join
LEFT JOIN
serialized_table ON serialized_table.array_field REGEXP CONCAT_WS('','.s:[0-9];s:', table_to_join.ID ,';.') ;
Take mention. I use index from 0 to 9 in table. If you have other indexes you must correct regexp