postgres: concat string with array - postgresql

Assume we have a column with text with next structure: ["A", "B", "C"],
how to concat it with array ARRAY['A','C','D','E'] and produce string ["A", "B", "C", "D", "E"] (string without repeated elements)?
postgres version is 9.4.8
Column data can be ["A", "B", "C"] or null, how it can be concatenated with ARRAY['A','C','D','E'] (actually it can be a string, but i need to add elements to existing string without repeating them), resulting string must have the following pattern ["A", "B", "C", "D", "E"]
Solved with script, that alternate db via pdo.

SELECT array_agg(x) FROM
(SELECT * FROM unnest(ARRAY['A', 'B', 'C'])
UNION
SELECT * FROM unnest(ARRAY['A','C','D','E'])
) a(x);
┌─────────────┐
│ array_agg │
├─────────────┤
│ {D,B,E,C,A} │
└─────────────┘
(1 row)

Transform the string to another array, unnest both and take the ordered UNION of both to form a new array:
SELECT ARRAY(
SELECT * FROM unnest(ARRAY['A','C','D','E'])
UNION
SELECT * FROM unnest(string_to_array(translate('["A", "B", "C"]', '[]"', ''), ', '))
ORDER BY 1
);
I removed the characters []" to proceed with the simple case. You would need to explain why you have them / need them ...
An ARRAY constructor is faster for the simple case.

Related

PostgreSQL, JsonB from a column with multiple keys pass it into multiple rows

I have a column in the DB which stores data from an API but it's as the following:
ID
jsonb column
1
{{"code1": "AB", "code2": "BC", "code3": "CD"}, {"code1": "DE", "code2": "EF"}}
2
{{"code1": "AB", "code2": "BC", "code3": "CD"}}
And I want to transform it like this:
ID
Code 1
Code 2
Code 3
1
AB
BC
CD
1
DE
EF
2
AB
BC
CD
OR
ID
Code 1
Code 2
Code 3
1
AB~DE
BC~EF
CD
2
AB
BC
CD
Thanks for you help!
I need help on building a SQL code for above queries
Assuming those values are in reality JSON arrays (e.g. [{"code1": "AB", "code2": "BC", "code3": "CD"}]), you can use jsonb_to_recordset()
select t.id,
r.*
from the_table t
cross join jsonb_to_recordset(t.data) as r("code1" text, "code2" text, "code3" text)
order by t.id

Convert column which contains array into new lines

I do have a table with the next data
val
---
["a", "b", "c"]
["d", "e", "f"]
is there a way to select and output it into a format of
val
----
a
b
c
d
e
f
Thanks!
That looks like a JSON array, so you can use:
select e.val
from the_table
cross join jsonb_array_elements(t.val) as e(val)
This assumes that val is defined as jsonb (which it should be). If it's "only" json use json_array_elements() instead. If it's not even json, but just text, then cast it val::jsonb
You can use the unnest function to achieve this. Documentation can be found in array functions: https://www.postgresql.org/docs/13/functions-array.html
SELECT unnest(val) should do the job

Fetching array data from jsonb postgresql

I am having a hard time in fetching values from jsonb where array is given.
{
"question1": [
"A",
"B",
"C"
],
"question2": [
"D",
"E",
"F"
],
"question3": "G",
}
for question3 I can fetch value as column_name ->> 'question3'::text and I have the value as "G"
but in the case of question1 and question2 I want to fetch value as an array and check if a particular element exists in question1 array or question2 array.
If you just want to filter the rows where a specific value exists in the JSON array, you can use the contains operator #>:
select *
from the_table
where the_column -> 'question1' #> '["A"]'
or the_column -> 'question2' #> '["A"]'
Use the postgres json function jsonb_array_elements / json_array_elements (link here) will get you the result.
jsonb_array_elements(column_name -> 'question1')
You can check type of the fetched json value the take action according to that: If it is string then simply you can print that or if it is array then you can proceed further and search for an element in the json array.
with tempJ(json_col) as (values('{"question1":[ "A", "B", "C" ], "question2":[ "D", "E", "F" ], "question3":"G"}'::jsonb))
SELECT case jsonb_typeof(json_col->'question2')
when 'array' then (json_col->'question2')
else (json_col->'question2') end
from tempJ
To search element from the array you can use:
select '[ "A", "B", "C" ]'::jsonb #> '"A"'

select all rows where array elements exist

I have a table:
CREATE TABLE test_array
(
id integer,
arr TEXT[]
);
I insert sample data:
INSERT INTO test_array(id, arr) VALUES (1, '{"a", "b", "c"}');
INSERT INTO test_array(id, arr) VALUES (2, '{"d", "f", "c"}');
INSERT INTO test_array(id, arr) VALUES (3, '{"a", "z", "i"}');
I want to get rows where elements {"a", "c"} is exist,
so the result must be:
'{"a", "b", "c"}'
'{"d", "f", "c"}'
'{"a", "z", "i"}'
I write query:
select * from test_array where arr #> '{"a"}' or arr #> '{"c"}';
but I want to make query without or, in one condition. Is it possible?
When I run select * from test_array where arr #> '{"a", "c"}';
it returns me only one row
https://rextester.com/ATMU4521
The #> means "contains" so all elements from the array on the right hand side must exist in the array on the left hand side. You are looking for the overlaps && operator which is described as "have elements in common":
select *
from test_array
where arr && array['a', 'c'];
I prefer the array[] notation to specify array constant as I don't need to think about nested quotes.

How to get only the jsonb of specific keys from postgres?

I'm aware that you can remove keys from a jsonb in postgres using something like this
select '{"a": 1, "b": 2, "c":3}'::jsonb -'a';
?column?
----------
{"b": 2 "c":3}
(1 row)
Is there a way to only grab specific keys? Like let's say I just want to get the key-value pair of just the 'a' key.
Something like this?
select '{"a": 1, "b": 2}'::jsonb + 'a' + 'b';
?column?
----------
{"a": 1, "b": 2}
(1 row)
EDIT: Changed the example to to show that I'd like to grab multiple keys-value pairs from the jsonb and not just one pair.
You can filter down to a single key fairly easily like so:
jsonb_object(ARRAY[key, jsonb_data -> key])
...or you can filter down to multiple keys:
(SELECT jsonb_object_agg(key, value) FROM jsonb_each(jsonb_data) WHERE key IN ('a', 'b'))
Or on a more complex condition, if you want:
(
SELECT jsonb_object_agg(key, value)
FROM jsonb_each(jsonb_data)
WHERE
key NOT LIKE '__%'
AND jsonb_typeof(value) != 'null'
)
These kinds of questions can be answered very easily by simply reading the documentation.
I actually found that this way works to.
select jsonb_build_object('key', column->'key') from table;
reference:
https://www.reddit.com/r/PostgreSQL/comments/73auce/new_user_to_postgres_can_i_grab_multiple_keys_of/
You can do this
SELECT jsonb_column->>'key_name_here' as 'alias_name_as_you_like' from table_name
In the case of the query asked above, it would be
select '{"a": 1, "b": 2, "c":3}'::jsonb->>'a'
You can get just the value like so:
select '{"a": 1, "b": 2}'::jsonb-> 'a';
If you must, you can transform that back into jsonb manually, or perhaps go through an array, hstore or other intermediate type. Here's the "manual" way
select ('{ "a": '||('{"a": 1, "b": 2}'::jsonb->'a')::text||'}')::jsonb
Paraphrasing the situation
we have a jsonb value and multiple keys in mind, a and c
select '{"a": 1, "b": 2, "c":3}'::jsonb - '{a,c}'::text[];
- is a tidy operator but gives us the opposite of what you want
{"b": 2}
solution is to wrap that in array(select jsonb_object_keys(...)) and perform the - again
select '{"a": 1, "b": 2, "c":3}'::jsonb - array(select jsonb_object_keys('{"a": 1, "b": 2, "c":3}'::jsonb - '{a,c}'::text[]));
you get a json with only those keys, a and c
{"a": 1, "c": 3}
If you want to filter multiple rows with JSONB documents in each of them:
-- Let's generate rows with JSONB column:
WITH s AS (SELECT generate_series(1, 100) num),
g AS (SELECT num, jsonb_build_object('a', s.num, 'b', s.num * 2) obj FROM s),
-- A "filter" adding (in my example only keys of "filter" document remain in result rows)
j AS (SELECT '{"a": "int", "c": "string"}'::jsonb AS filter),
a AS (SELECT (ARRAY(SELECT jsonb_object_keys(filter))) AS ar FROM j),
-- Useless keys removing
o AS (SELECT jsonb_object_agg(l.key, l.value) obj
FROM g, LATERAL jsonb_each(g.obj) l, a
WHERE l.key = ANY(a.ar)
GROUP BY num)
SELECT * FROM o ORDER BY obj->'a';
Begin;
CREATE TEMPORARY TABLE test (id serial, jdoc jsonb);
insert into test(jdoc) values('{"a": {"b":"foo"}}');
insert into test(jdoc) values('{"a": "test"}');
insert into test(jdoc) values('{"a":[2,3,4]}');
insert into test(jdoc) values('{"b":[2,3,4]}');
commit;
select (jdoc->'a') from test where jdoc ? 'a'
will get all the specific key's value.
If you want JSONB of the specific key: select jdoc from test where jdoc ? 'a'