I'm looking to query a table for a distinct list of values in a given JSON column.
In the code snippet below, the Survey_Results table has 3 columns:
Name, Email, and Payload. Payload is the JSON object to I want to query.
Table Name: Survey_Results
Name Email Payload
Ying SmartStuff#gmail.com [
{"fieldName":"Product Name", "Value":"Calculator"},
{"fieldName":"Product Price", "Value":"$54.99"}
]
Kendrick MrTexas#gmail.com [
{"fieldName":"Food Name", "Value":"Texas Toast"},
{"fieldName":"Food Taste", "Value":"Delicious"}
]
Andy WhereTheBass#gmail.com [
{"fieldName":"Band Name", "Value":"MetalHeads"}
{"fieldName":"Valid Member", "Value":"TRUE"}
]
I am looking for a unique list of all fieldNames mentioned.
The ideal answer would be query giving me a list containing "Product Name", "Product Price", "Food Name", "Food Taste", "Band Name", and "Valid Member".
Is something like this possible in Postgres?
Use jsonb_array_elements() in a lateral join:
select distinct value->>'fieldName' as field_name
from survey_results
cross join json_array_elements(payload)
field_name
---------------
Product Name
Valid Member
Food Taste
Product Price
Food Name
Band Name
(6 rows)
How to find distinct Food Name values?
select distinct value->>'Value' as food_name
from survey_results
cross join json_array_elements(payload)
where value->>'fieldName' = 'Food Name'
food_name
-------------
Texas Toast
(1 row)
Db<>fiddle.
Important. Note that the json structure is illogical and thus unnecessarily large and complex. Instead of
[
{"fieldName":"Product Name", "Value":"Calculator"},
{"fieldName":"Product Price", "Value":"$54.99"}
]
use
{"Product Name": "Calculator", "Product Price": "$54.99"}
Open this db<>fiddle to see that proper json structure implies simpler and faster queries.
Related
I'm trying to join two tables of data using ID's. ID's from one table correspond to an ID+5 on the other table.
I've tried using this code:-
SELECT
"Stage",
"Type",
"Contract Type (Business Or Personal)",
"Requested Vehicle",
"Short Vehicle",
"Mileage Per Year",
"Initial Rental",
"Initial Rental £",
"Contract Length",
Opportunities."Advertised Rental",
Contacts.Id,
Opportunities.Id,
"First Name",
"Full Name",
"Email",
"Mobile",
"Phone",
"Contact Owner Name",
Contacts."Lead Source",
Contacts."Created Time"
FROM "Opportunities"
RIGHT JOIN "Contacts" ON Opportunities.Id = Contacts.Id
ORDER BY Contacts."Created Time"
This results in only the contacts data showing up in a table with the opportunities data blank. This is because the ID's are different by 5. So I tried:-
RIGHT JOIN "Contacts" ON Opportunities.Id-5 = Contacts.Id
but that didn't work and I couldn't find anything on the internet that was relevant. Any help would be appreciated as I'm an inexperienced coder.
Thanks,
James
Have you just tried using an alias for a column?
SELECT
"Stage",
"Type",
"Contract Type (Business Or Personal)",
"Requested Vehicle",
"Short Vehicle",
"Mileage Per Year",
"Initial Rental",
"Initial Rental £",
"Contract Length",
Opportunities."Advertised Rental",
Contacts.Id,
Opportunities.Id,
"First Name",
"Full Name",
"Email",
"Mobile",
"Phone",
"Contact Owner Name",
Contacts."Lead Source",
Contacts."Created Time"
FROM (SELECT Opportunities.*, "Id" - 5 AS "ContactId" FROM "Opportunities") AS Opps
RIGHT JOIN "Contacts" ON Opps.ContactId = Contacts.Id
ORDER BY Contacts."Created Time"
Side note, it's probably good to scrub your data to have a cleaner reference than an offset ID if you have permissions to do that.
I have a column in prestodb that is a list of dictionaries:
[{"id": 45238, "kind": "product", "name": "Ball", "category": "toy"}, {"id": 117852, "kind": "service", "name": "courier", "category": "transport"}]
is a there a way to expand this column to get something like this:
id kind name category
4528 product Ball toy
117852 service courier transport
Also sometimes the key's can be different from the example above also can have more key's than the 4 above
I am trying:
with cte as ( select cast(divs as json) as json_field from table)
select m['id'] id,
m['kind'] kind,
m['name'] name,
m['category'] category
from cte
cross join unnest(cast(json_field as array(map(varchar, json)))) as t(m)
Error:
INVALID_CAST_ARGUMENT: Cannot cast to array(map(varchar, json)). Expected a json array, but got [{"id": 36112, "kind"....
Assuming your data contains json - you can cast it to array of maps from varchar to json (array(map(varchar, json))) and then use unnest to flatten the array:
WITH dataset (json_str) AS (
VALUES (json '[{"id": 45238, "kind": "product", "name": "Ball", "category": "toy"}, {"id": 117852, "kind": "service", "name": "courier", "category": "transport"}]')
)
select m['id'] id,
m['kind'] kind,
m['name'] name,
m['category'] category
from dataset
cross join unnest(cast(json_str as array(map(varchar, json)))) as t(m)
id
kind
name
category
45238
product
Ball
toy
117852
service
courier
transport
UPD
If original column type is varchar - use json_parse to convert it to json.
Breaking my head on this. In Snowflake my field city_info looks like (for 3 sample records)
[{"name": "age", "content": 35}, {"name": "city", "content": "Chicago"}]
[{"name": "age", "content": 20}, {"name": "city", "content": "Boston"}]
[{"name": "city", "content": "New York"}, {"name": "age", "content": 42}]
I try to extract a column city from this
Chicago
Boston
New York
I tried to flatten this
select *
from lateral flatten(input =>
select city_info::VARIANT as event
from data
)
And from there I can derive the value, but this only allows me to do this for 1 row (so I have to add limit 1 which doesn't makes sense, as I need this for all my rows).
If I try to do it for the 3 rows it tells me subquery returns more than one row.
Any help is appreciated! Chris
You could write it as:
SELECT value:content::string AS city_name
FROM tab,
LATERAL FLATTEN(input => tab.city_info)
WHERE value:name::string = 'city'
I have 2 simple tables in a SQLite db and a nodejs, express api endpoint that should get results by student and have the subjects as a nested array of objects.
Tables:
Student(id, name) and Subject(id, name, studentId)
This is what I need to result to look like:
{
"id": 1,
"name": "Student name",
"subjects":
[{
"id": 1,
"name": "Subject 1"
},
{
"id": 2,
"name": "Subject 2"
}]
}
How can I write a query to get this result?
If your version of sqlite was built with support for the JSON1 extension, it's easy to generate the JSON from the query itself:
SELECT json_object('id', id, 'name', name
, 'subjects'
, (SELECT json_group_array(json_object('id', subj.id, 'name', subj.name))
FROM subject AS subj
WHERE subj.studentid = stu.id)) AS record
FROM student AS stu
WHERE id = 1;
record
---------------------------------------------------------------------------------------------------
{"id":1,"name":"Student Name","subjects":[{"id":1,"name":"Subject 1"},{"id":2,"name":"Subject 2"}]}
It seems that all you need is a LEFT JOIN statement:
SELECT subject.id, subject.name, student.id, student.name
FROM subject
LEFT JOIN student ON subject.studentId = student.id
ORDER BY student.id;
Then just parse the rows of the response into the object structure you require.
I would like to select all rows from my database where one row contains at least two terms from a set of words/array.
As an example:
I have the following array:
'{"test", "god", "safe", "name", "hello", "pray", "stay", "word", "peopl", "rain", "lord", "make", "life", "hope", "whatever", "makes", "strong", "stop", "give", "television"}'
and I got a tweet dataset stored in the database. So i would like to know which tweets (column name: tweet.content) contain at least two of the words.
My current code looks like this (but of course it only selects one word...):
CREATE OR REPLACE VIEW tweet_selection AS
SELECT tweet.id, tweet.content, tweet.username, tweet.geometry,
FROM tweet
WHERE tweet.topic_indicator > 0.15::double precision
AND string_to_array(lower(tweet.content)) = ANY(SELECT '{"test", "god", "safe", "name", "hello", "pray", "stay", "word", "peopl", "rain", "lord", "make", "life", "hope", "whatever", "makes", "strong", "stop", "give", "television"}'::text[])
so the last line needs to be adjustested somehow, but i have no idea how - maybe with a inner join?!
I have the words also stored with a unique id in a different table.
A friend of mine recommended getting a count for each row, but i have no writing access for adding an additional column in the original tables.
Background:
I am storing my tweets in a postgres database and I applied a LDA (Latent dirichlet allocation) on the dataset. Now i got the generated topics and the words associated with each topic (20 topics and 25 words).
select DISTINCT ON (tweet.id) tweet.id, tweet.content, tweet.username, tweet.geometry
from tweet
where
tweet.topic_indicator > 0.15::double precision
and (
select count(distinct word)
from
unnest(
array['test', 'god', 'safe', 'name', 'hello', 'pray', 'stay', 'word', 'peopl', 'rain', 'lord', 'make', 'life', 'hope', 'whatever', 'makes', 'strong', 'stop', 'give', 'television']::text[]
) s(word)
inner join
regexp_split_to_table(lower(tweet.content), ' ') v (word) using (word)
) >= 2