PostgreSQL dynamically SELECT last json array value - json

How do I dynamically SELECT the last array value in a JSON type column in PostgreSQL?
id: 2927
material_size: [".016 x 1.156","0","1"]
I could statically retrieve the last value "1" using:
SELECT material_size->>2 AS material_size FROM table_name;
However that would always get the second record instead of the last record (if the number of values isn't exactly three).

You can get the length of the JSON array and use that (minus one) as the index:
with t1 as (select 2927 id, '[".016 x 1.156","0","1"]'::json material_size)
select material_size->>(json_array_length(material_size)-1) from t1;
See http://www.postgresql.org/docs/9.4/static/functions-json.html.

You can use negative index to query elements in a JSON value from the end:
SELECT material_size->>-1 AS material_size FROM table_name;

Related

Snowflake latteral flatten data types

I have a table containing an id column and a json column(variant data type). I want to flatten the data, make the value column a variant, assign each value in the value column a data type if a condition is met, then eventually pivot the data and have each column be the correct data type.
Example code that doesn't work:
with cte as (
select
1 as id,
parse_json('{
"field1":"TRUE",
"field2":"some string",
"field3":"1.035",
"field4":"097334"
}') as my_output
)
select
id,
key,
to_variant(
case
when value in ('true', 'false') then value::boolean
when value like ('1.0') then value::decimal
else value::string
end) as value
from cte, lateral flatten(my_output)
Ultimately, I'd like to pivot the data and have a wide table with columns id, field1, field2, etc. where field1 is boolean, field2 is string, field3 is a decimal etc.
This is just a simple example, instead of 4 fields, I'm dealing with hundreds.
Is this possible?
For the pivot, I'm using dbt_utils.get_column_values to get the column names dynamically. I'd really prefer a solution that doesn't involve listing out the column names, especially since there are hundreds.
Since you'd have to define each column in your PIVOT statement, anyway, it'd probably be much easier to simply select each attribute directly and cast to the correct data type, rather than using a lateral flatten.
select
my_output.field1::boolean,
my_output.field2::string,
my_output.field3::decimal(5,3),
my_output.field4::string
from cte;
Alternatively, if you want this to be dynamically created, you could create a stored procedure that dynamically uses your json to create a view over your table that has this select in it.
Solution ended up being
select
id,
key,
ifnull(try_parse_json(value), value) as value_mod,
typeof(value_mod)
from cte, lateral flatten(my_output)
Leading zeros are removed so things like zip codes have to be accounted for.

sort the json array in postgresql

create table sort(authorized json);
insert into sort values('{"name":"Authorized","states":[{"state_code":"CT","state_name":"Connecticut","is_checked":false},{"state_code":"NJ","state_name":"New Jersey","is_checked":false},{"state_code":"SC","state_name":"South Carolina","is_checked":false},{"state_code":"FL","state_name":"Florida","is_checked":false},{"state_code":"MT","state_name":"Montana","is_checked":false},{"state_code":"GA","state_name":"Georgia","is_checked":false},
{"state_code":"IA","state_name":"Iowa","is_checked":false},{"state_code":"AR","state_name":"Arkansas","is_checked":false},{"state_code":"UT","state_name":"Utah","is_checked":false},{"state_code":"ID","state_name":"Idaho","is_checked":false},{"state_code":"IL","state_name":"Illinois","is_checked":false},{"state_code":"IN","state_name":"Indiana","is_checked":false},{"state_code":"MA","state_name":"Massachusetts","is_checked":false},{"state_code":"MI","state_name":"Michigan","is_checked":false},{"state_code":"MS","state_name":"Mississippi","is_checked":false},{"state_code":"NM","state_name":"New Mexico","is_checked":false},{"state_code":"NV","state_name":"Nevada","is_checked":false},{"state_code":"RI","state_name":"Rhode Island","is_checked":false},{"state_code":"SD","state_name":"South Dakota","is_checked":false},{"state_code":"UT","state_name":"Utah","is_checked":false},{"state_code":"WV","state_name":"West Virginia","is_checked":false},{"state_code":"SD","state_name":"South Dakota","is_checked":false},
{"state_code":"WV","state_name":"West Virginia","is_checked":false}]}')
I want that this json sort according to state_code after update it looks like
{"name":"Authorized","states":[{"state_code":"AR","state_name":"Arkansas","is_checked":false},{"state_code":"CT","state_name":"Connecticut","is_checked":false},{"state_code":"FL","state_name":"Florida","is_checked":false},{"state_code":"GA","state_name":"Georgia","is_checked":false},
{"state_code":"IA","state_name":"Iowa","is_checked":false},{"state_code":"ID","state_name":"Idaho","is_checked":false},{"state_code":"IL","state_name":"Illinois","is_checked":false},{"state_code":"IN","state_name":"Indiana","is_checked":false},{"state_code":"MA","state_name":"Massachusetts","is_checked":false},{"state_code":"MI","state_name":"Michigan","is_checked":false},{"state_code":"MS","state_name":"Mississippi","is_checked":false},{"state_code":"MT","state_name":"Montana","is_checked":false},{"state_code":"NJ","state_name":"New Jersey","is_checked":false},{"state_code":"NM","state_name":"New Mexico","is_checked":false},{"state_code":"NV","state_name":"Nevada","is_checked":false},{"state_code":"RI","state_name":"Rhode Island","is_checked":false},{"state_code":"SC","state_name":"South Carolina","is_checked":false},{"state_code":"SD","state_name":"South Dakota","is_checked":false},{"state_code":"UT","state_name":"Utah","is_checked":false},{"state_code":"WV","state_name":"West Virginia","is_checked":false},{"state_code":"SD","state_name":"South Dakota","is_checked":false},{"state_code":"UT","state_name":"Utah","is_checked":false},
{"state_code":"WV","state_name":"West Virginia","is_checked":false}]}
try this:
select substr(column_name, position ('state_code":"' in column_name)+13,4) as stateCode
from table_name
order by stateCode asc/desc
note:the value 13 represents the lenght of field (state_code":) and 4 represents value of field ("AR")
might need to tweak a little according to you table and column. The select part would select your desired element then you only have to order it by asc or desc.
You can get the results ordered when retrieving the data through sorting within the subquery while extracting the concerned array(states) as a seperate column, and then aggregating the individual objects of the array back while adhering name element of the object such as
SELECT JSON_AGG(
JSON_BUILD_OBJECT( 'name', name, 'states', states)
) AS authorized
FROM
(
SELECT authorized->'name' AS name, j.states
FROM sort,
JSON_ARRAY_ELEMENTS(authorized->'states') AS j(states)
ORDER BY j.states->>'state_code' ) AS ns
Demo

Match cut-string mysql

How do I match cut string from mysql
For exampe in the column the value is googleduo or googlehangout, but the string I have is google.
SELECT name FROM table WHERE name LIKE '%".$string."%' LIMIT 1
This doesnt return record. At least it return one by finding the closest time
OR maybe the case is vice-versa, I have string googleduo, but the value in the table is google. I want to return google.
if you need to check does the substring is present in the column value use one of:
SELECT name FROM table WHERE LOCATE(substring, name);
-- or
SELECT name FROM table WHERE INSTR(name, substring);
The functions returns the position of the substring in the column value if present and 0 otherwise. Non-zero is treated as TRUE, zero as FALSE.
The functions do absolutely the same and differs in parameters order only.
If you need backward condition then simply add NOT:
SELECT name FROM table WHERE NOT LOCATE(substring, name);
-- or
SELECT name FROM table WHERE ! LOCATE(substring, name);

How to extract a value from JSON that repeats multiple times?

I have the following table:
I need to create a select that returns me something like this:
I have tried this code:
SELECT Code, json_extract_path(Registers::json,'sales', 'name')
FROM tbl_registers
The previous code returns me a NULL in json_extract_path, I have tried the operator ::json->'sales'->>'name', but doesn't work too.
You need to unnest the array, and the aggregate the names back. This can be done using json_array_elements with a scalar sub-query:
select code,
(select string_agg(e ->> 'name', ',')
from json_array_elements(t.products) as x(e)) as products
from tbl_registers t;
I would also strongly recommend to change your column's type to jsonb
step-by-step demo:db<>fiddle
SELECT
code,
string_agg( -- 3
elems ->> 'name', -- 2
','
) as products
FROM tbl_registers,
json_array_elements(products::json) as elems -- 1
GROUP BY code
If you have type text (strictly not recommended, please use appropriate data type json or jsonb), then you need to cast it into type json (I guess you have type text because you do the cast already in your example code). Afterwards you need to extract the array elements into one row per element
Fetch the name value
Reaggregate by grouping and use string_agg() to create the string list

sql query is not working in case of number is in decimal

I am using the following query, it is showing the empty result but the record exist in table.
Please let me know how can do it
select * from wp_rg_lead_detail where lead_id=5047 and field_number=1.6
select * from wp_rg_lead_detail where lead_id=5047 and field_number=1.6
in both case query return the empty result.but data exist in table.
data type of the field_number is float in database.
Change the column to to decimal or numeric,they store exact numeric data values.Floats are always approximative numbers(in the way that are stored)
EDIT:Try it like this
select * from wp_rg_lead_detail where lead_id=5047 and format(field_number,1)=1.6