Is there a Hiveql function using which we can pull records from a table where a JSON type column has a specific value for a key? - hive

I'm looking to get count of records in which a column(type) of json type has certain key:value in table named product_type.
_______________________________________________________
id | product | type |
1 | product_1 | {"costly": true, "l_type": true} |
2 | product_2 | {"costly": false, "l_type": true} |
3 | product_3 | {"costly": false, "l_type": true} |
4 | product_4 | {"costly": false, "l_type": true} |
_______________________________________________________
Something like-
select count(id) from product_table where type has {"costly": false}
What I have tried:
select count(*) from product_table where type LIKE '%"costly": false%'
-> which is not yielding any results.
Expecting to get:
3 ( as there are 3 records that has value as false in type column for the key costly.)

I got it resolved:
select count(*) from product_table where get_json_object(type,$.costly) is true;

Related

Update of value in array of jsonb returns error"invalid input syntax for type json"

I have a column of type jsonb which contains json arrays of the form
[
{
"Id": 62497,
"Text": "BlaBla"
}
]
I'd like to update the Id to the value of a column word_id (type uuid) from a different table word.
I tried this
update inflection_copy
SET inflectionlinks = s.json_array
FROM (
SELECT jsonb_agg(
CASE
WHEN elems->>'Id' = (
SELECT word_copy.id::text
from word_copy
where word_copy.id::text = elems->>'Id'
) THEN jsonb_set(
elems,
'{Id}'::text [],
(
SELECT jsonb(word_copy.word_id::text)
from word_copy
where word_copy.id::text = elems->>'Id'
)
)
ELSE elems
END
) as json_array
FROM inflection_copy,
jsonb_array_elements(inflectionlinks) elems
) s;
Until now I always get the following error:
invalid input syntax for type json
DETAIL: Token "c66a4353" is invalid.
CONTEXT: JSON data, line 1: c66a4353...
The c66a4535 is part of one of the uuids of the word table. I don't understand why this is marked as invalid input.
EDIT:
To give an example of one of the uuids:
select to_jsonb(word_id::text) from word_copy limit(5);
returns
+----------------------------------------+
| to_jsonb |
|----------------------------------------|
| "078c979d-e479-4fce-b27c-d14087f467c2" |
| "ef288256-1599-4f0f-a932-aad85d666c9a" |
| "d1d95b60-623e-47cf-b770-de46b01042c5" |
| "f97464c6-b872-4be8-9d9d-83c0102fb26a" |
| "9bb19719-e014-4286-a2d1-4c0cf7f089fc" |
+----------------------------------------+
As requested the respective columns id and word_id from the word table:
+---------------------------------------------------+
| row |
|---------------------------------------------------|
| ('27733', '078c979d-e479-4fce-b27c-d14087f467c2') |
| ('72337', 'ef288256-1599-4f0f-a932-aad85d666c9a') |
| ('72340', 'd1d95b60-623e-47cf-b770-de46b01042c5') |
| ('27741', 'f97464c6-b872-4be8-9d9d-83c0102fb26a') |
| ('72338', '9bb19719-e014-4286-a2d1-4c0cf7f089fc') |
+---------------------------------------------------+
+----------------+----------+----------------------------+
| Column | Type | Modifiers |
|----------------+----------+----------------------------|
| id | bigint | |
| value | text | |
| homonymnumber | smallint | |
| pronounciation | text | |
| audio | text | |
| level | integer | |
| alpha | bigint | |
| frequency | bigint | |
| hanja | text | |
| typeeng | text | |
| typekr | text | |
| word_id | uuid | default gen_random_uuid() |
+----------------+----------+----------------------------+
I would suggest you to modify your sub query as follow :
update inflection_copy AS ic
SET inflectionlinks = s.json_array
FROM
(SELECT jsonb_agg(CASE WHEN wc.word_id IS NULL THEN e.elems ELSE jsonb_set(e.elems, array['Id'], to_jsonb(wc.word_id::text)) END ORDER BY e.id ASC) AS json_array
FROM inflection_copy AS ic
CROSS JOIN LATERAL jsonb_path_query(ic.inflectionlinks, '$[*]') WITH ORDINALITY AS e(elems, id)
LEFT JOIN word_copy AS wc
ON wc.id::text = e.elems->>'Id'
) AS s
The LEFT JOIN clause will return wc.word_id = NULL when there is no wc.id which corresponds to e.elems->>'id', so that e.elems is unchanged in the CASE.
The ORDER BY clause in the aggregate function jsonb_agg will ensure that the order is unchanged in the jsonb array.
jsonb_path_query is used instead of jsonb_array_elements so that to not raise an error when ic.inflectionlinks is not a jsonb array and it is used in lax mode (which is the default behavior).
see the test result in dbfiddle

Nesting jsonb in postgres without converting to jsonb[]

I have 1 table with 2 columns 1 is an index that holds the group number and a column of jsonb data
| Index | payload |
|----------------|----------------|
| 1 | {jsonb} |
| 1 | {jsonb} |
| 2 | {jsonb} |
| 2 | {jsonb} |
I then want to nest the payload into another jsonb, but it must not be an array.
Expected Output:
| Index | payload |
|----------------|----------------|
| 1 |{{jsonb},{jsonb}}|
| 2 |{{jsonb},{jsonb}}|
Actual Output:
| Index | payload |
|----------------|----------------|
| 1 |[{{jsonb},{jsonb}}]|
| 2 |[{{jsonb},{jsonb}}]|
SELECT index, jsonb_agg(payload) as "payload"
FROM table1
GROUP BY 1
ORDER BY 1
As you can see the output does aggregate the columns into a jsonb, but also converts it into an array. Is it possible to remove the array?
You can create your own aggregate that just appends the JSONB values:
create aggregate jsonb_append_agg(jsonb)
(
sfunc = jsonb_concat(jsonb, jsonb),
stype = jsonb
);
Then you can do:
SELECT index, jsonb_append_agg(payload) as "payload"
FROM table1
GROUP BY 1
ORDER BY 1

Snowflake - using json_parse and select distinct to un-nested column and compare with another column

I have 2 columns, 1 is a nested column named custom_field and the other is sales_id I want to compare the sales_id_2 values in custom_field with sales_id column
I've tried this but it didn't work:
select distinct parse_json(custom_fields) as CUSTOM_FIELDS
from my_table where custom_fields:sales_id_2 = sales_id;
but I get the error:
SQL compilation error: error line 1 at position 111 Invalid argument
types for function 'GET': (VARCHAR(16777216), VARCHAR(2)).
+-----------------------------------------------------+
| custom_field | sales_id |
|-----------------------------------------------------|
| | |
| { | 235324115 |
| "sales_id_2": 235324115, | 1234351 |
| "g": 12, | |
| "r": 255 | |
| } | |
| { | 678322341 |
| "sales_id_2": 1234351, | 5648561 |
| "g": 13, | |
| "r": 254 | |
| } | |
I'm hoping to see empty results, because I believe sales_id_2 is the same as sales_id
:: is for casting, plus you are trying a JSON operation on a varchar column. try this
select distinct parse_json(custom_fields) as CUSTOM_FIELDS from my_table where parse_json(custom_fields):sales_id_2 = sales_id;

Postgresql: select rows by OR condition - including going through json array

I have a table created by following query:
create table data
(
id integer not null unique,
owner text,
users jsonb not null
);
The table looks like this:
+----+-------+---------------------------------------------+
| id | owner | users |
+----+-------+---------------------------------------------+
| 1 | alice | [] |
| 2 | bob | [{"accountId": "alice", "role": "manager"}] |
| 3 | john | [{"accounId": "bob", "role": "guest"}] |
+----+-------+---------------------------------------------+
I need to get rows 1 and 2 on behalf of Alice.
Getting owner-based rows works perfect:
SELECT *
FROM data
WHERE owner = 'alice'
Getting jsonb-based rows is a little trickier though managable:
SELECT *
FROM data, jsonb_array_elements(users) x
WHERE (x ->> 'accountId') = 'alice'
But getting them together gets me just the jsonb-based ones:
SELECT *
FROM data, jsonb_array_elements(users) x
WHERE owner = 'alice' OR (x ->> 'accountId') = 'alice'
How do I get the selection that looks like following?
+----+-------+---------------------------------------------+
| id | owner | users |
+----+-------+---------------------------------------------+
| 1 | alice | [] |
| 2 | bob | [{"accountId": "alice", "role": "manager"}] |
+----+-------+---------------------------------------------+
Even better if I can get a selection that looks like this
+----+----------+
| id | role |
+----+----------+
| 1 | owner |
| 2 | manager |
+----+----------+
The problem is with the empty json array, which evicts the corresponding row from the result set when cross joined with jsonb_array_elements(). Instead, you can make a left join lateral:
select d.*
from data d
left join lateral jsonb_array_elements(d.users) as x(js) on 1 = 1
where 'alice' in (d.owner, x.js ->> 'accountId')
Note that, if your array always contains 0 or 1 element, tyou don't need the lateral join - your query would be simpler phrased as:
select d.*
from data d
where 'alice' in (d.owner, d.data -> 0 ->> 'accountId')
Demo on DB Fiddle - both queries return:
id | owner | users
-: | :---- | :------------------------------------------
1 | alice | []
2 | bob | [{"role": "manager", "accountId": "alice"}]

WHERE statement with duplicate column names over JOIN - PostgreSQL

I am trying to join two tables, a plans table and a plan_details table. Below are two examples of what the tables look like.
PLANS Table
+---------+------+-----------+
| user_id | plan | is_active |
+---------+------+-----------+
| 1 | 10 | true |
| 1 | 11 | false |
| 2 | 11 | true |
PLAN_DETAILS Table
+---------+------+-------+-----------+
| plan_id | cost | price | is_active |
+---------+------+-------+-----------+
| 10 | 19 | 199 | true |
| 11 | 13 | 149 | true |
I only want to only pull the active plan cost and the price related to each user. Right now, my knex statement is:
knex('plans')
.where({
user_id: 1,
is_active: 'true'
})
.select(
'plans.plan',
'plan_details.cost',
'plan_details.price'
)
.join('plan_details as plan_details', 'plan_details.plan_id', 'plans.plan')
.then(function (user_plan_id) {
console.log(user_plan_id);
});
Now if I keep the is_active: 'true' in there then I get a Unhandled rejection error: column reference "is_active" is ambiguous. If I take out the is_active part, well then I get information for both of the plans that reference the user even though I only want the info regarding which plans are active for the user.
How do I get only the active plans for a user? I am using KNEX.JS as my ORM, but I am happy to use raw SQL as well for this.
With knex this should do:
knex('plans')
.select(
'plans.plan',
'plan_details.cost',
'plan_details.price'
)
.join('plan_details as plan_details', 'plan_details.plan_id', 'plans.plan')
.where('plan.user_id', 1)
.where('plan.is_active', true)
.then(function (user_plan_id) {
console.log(user_plan_id);
});
SQL would be similar to:
select
plans.plan,
plan_details.cost,
plan_details.price
from plan
join plan_details on plans.plan = plan_details.plan_id
where plan.is_active