How to convert text to jsonb entirely for a postgresql column - json

What I have is a text column in Postgresql which I want to convert to JSONB column.
What I have tried is this:
CREATE TABLE test (id serial, sec text, name text);
INSERT INTO test (id, sec, name) VALUES (1,'{"gender":"male","sections":{"a":1,"b":2}}','subject');
ALTER TABLE test ALTER COLUMN sec TYPE JSONB USING sec::JSONB;
This did convert the text column to jsonb.
However, if I try to query:
SELECT sec->>'sections'->>'a' FROM test
I get an error.
I see the conversion is done only at one level(i.e: sec->>'sections' works fine).
The query SELECT pg_typeof(name->>'sections') from test; gives me column type as text.
Is there a way I can convert the text to jsonb entirely, such that I can query SELECT sec->>'sections'->>'a' FROM test; successfully?
I don't want to convert the text to json in the query like below, as I need to create index on 'a' later.
select (sec->>'sections')::json->>'a' from test;

The operator ->> gives a text as a result. Use -> if you want jsonb:
select
pg_typeof(sec->>'sections') a,
pg_typeof(sec->'sections') b
from test;
a | b
------+-------
text | jsonb
(1 row)
Use:
select sec->'sections'->>'a'
from test;

Or better, yet, use the operator #>>:
SELECT sec #>> '{sections,a}' FROM test;
And to use this in an expression index you need extra parentheses:
CREATE INDEX foo ON test ((sec #>> '{sections,a}'));
Make sure to use a matching expression (without parentheses) in queries to allow index usage.

Related

Best way to check if query mysql table with JSON column if equals a JSON value?

Hi I have a mysql table with a JSON column. Lets say table name is example_table and JSON column name is json_column and I have a JSON value x that I want to query by.
I was wondering if there is someway to query on the table to see if a value inside example_table that has a json_column value equal to x.
So something like this:
select * from example_table where json_column=x;
Example where x is a JSON array.
select * from example_table where json_column='["12345", "56789"]';
The above query does not work. I was wondering how I can query the table this way?
I figured it out.
select * from example_table where json_column=CAST('["12345", "56789"]' AS JSON);

MySql json reverse search

I have a MySQL table with a column of type json. The values of this columns are json array not json object. I need to find records of this table that at least one value of their json column is substring of the given string/phrase.
Let's suppose the table is looks like this:
create table if not exists test(id int, col json);
insert into test values (1, '["ab", "cd"]');
insert into test values (2, '["ef", "gh", "ij"]');
insert into test values (3, '["xyz"]');
If the input string/phrase is "acf ghi z" the second column must be returned as the result, because "gh" is a substring of the input. I read a lot about json_contains, json_extract, json_search and even json_overlaps but couldn't manage to solve this problem.
What is the correct sql syntax to retrieve the related rows?
MySQL version is 8.0.20
You can use json_table() to extract the JSON array as rows in a table. Then just filter:
select *
from test t cross join
json_table(t.col, '$[*]' columns (str varchar(255) path '$')) j
where 'acf ghi z' like concat('%', j.str, '%');
Here is a db<>fiddle.

MySQL first_value on varchar column returns records in wrong format

first_value function in MySQL returns varchar column in unexpected format.
I got a table 'test' with two columns
create table test (col1 varchar(10), col2 integer);
and has records like this,
when I run first_value function I get records like this
select *, first_value(col1) over(partition by col1 order by col2 desc) as max_col1
from test;
is this because first_value works only for numeric fields?
is this because first_value works only for numeric fields?
No, first_value() works as well for the varchar data type.
The results you get are correct but in hexadecimal format!
0x6B657931 is key1
0x6B657932 is key2
0x6B657933 is key3
So this could be a collation issue or a problem with the software you are using.
If you are using a fiddle-like site, then it is not strange that the results come as they are.
Anyway, you can find more here: https://dev.mysql.com/doc/refman/8.0/en/charset-syntax.html
If the problem persists, you can always use the unhex() function:
select unhex('6B657931')
will return:
key1
Or:
select CAST(0x6B657931 AS CHAR)
will also return:
key1
See the demo.

Postgres Select Where JSON Field Not Null

I have a table which has a column called warnings. the column value for 2 rows is shown bellow
warnings
-------------------------------------------------------------------
{"isNew":false,"fieldWarnings":[],"dupId":null,"conflictIds":[]}
{"isNew":false,"fieldWarnings":[],"dupId":3763,"conflictId":null}
I want an sql statement that will select the top row but not the bottom row. i tried this sql query but it selects both rows
select warnings from table where cast(warnings->>'dubId' AS TEXT) is null;
You have dubId in your query but the JSON property is dupId. I think you've just got a typo!
Try this instead:
select warnings from table where cast(warnings->>'dupId' AS TEXT) is null;
Also, the ->> operator returns the field value as text already so you shouldn't need the cast:
select warnings from table where warnings->>'dupId' is null;

How do I handle moving data from tinyint into a text field

We have a field which stores data (e.g. 1, 0) in a tinyint(1) column, and I have to move this into a text column and a simple transformation stores the data in text field with additional spaces instead of just 1 or 0. How should I do this correctly?
create table A (id, foo tinyint(1));
create table B (id, bar text);
I am trying to copy all elements of A into B using insert into B (id, bar) select id, foo from A; which is causing the transformation problem.
There is nothing wrong with your insert statement. The problem lies with the way MySQL compares strings.
Even the following query will match:
SELECT * FROM B where TRIM(bar) = '1 ';
The following works correctly (IE, does not match):
SELECT * FROM B where bar LIKE '1 ';
MySQL masters implicit conversion. Since you are converting a number to a string type, I don't see any problem which could occur. Therefore, something like UPDATE table1 SET text_column = CONCAT(' ',tinyint_column,' ') should work.