Scala, Doobie, PostgreSQL - how to select from array/jsonb column? - sql

I have a simple db table:
create table if not exists players
(
id bigint,
name text,
results text[]
);
Now I would like to create select query, where I want only rows with passed results. So I created a scala code with doobie:
def getPlayers(id: Int, result: String): Query[Int] = {
sql"select id from players where results ? $result".query[Int]
}
But it didn't work as expected. My question is how to select from array column in postgresql? Currently I have results as an array, but I could change it to jsonb if it is easier.

You can use the following query:
select id from players where $result = any(results);
You can find more information here:
https://www.postgresql.org/docs/current/functions-comparisons.html

Related

Get first item of 2d array entries in postgreSQL

I got a postgres function that gives me this (sample) 2D array
{{0.82,60.64,1006},{2.0,59.64,1006},{9.9,60.304,999}}
I want to get the first item of each row, like this:
{0.82,2.0,9.9,}
Any way of doing this directly on Postgres/SQL? Thanks
PostrgeSql provides array ops you want. Demo
CREATE TABLE sample (
id int,
va decimal[3][3]
);
INSERT INTO sample
VALUES (1, '{{0.82,60.64,1006},{2.0,59.64,1006},{9.9,60.304,999}}');
select id, array_agg(v) res
from (
select id, unnest(va[:][1:1]) v
from sample
) t
group by id
Returns
id res
1 {0.82,2.0,9.9}

Postgresql JSON column check value exists in array of json

I have a database schema like the following where I have a Children record table
CREATE TABLE Children (
name varchar(100),
friends JSON NOT NULL,
);
INSERT INTO Children (name,friends)
VALUES('Sam',
array['{"name":"Rakesh","country":"Africa"}',
'{"name":"Ramesh","country":"India"}']::json[]);
Now I need to query the data and display it only if the name of the friend is like '%Ra'. Structure of the JSON data is consistent.
If you have json[] as data type then you can use unnest and then write your query, or if it is json then you can use json_array_elements.
Below code considers json[] data type -
select * from Children
where name in (
select name from (
select name, unnest(friends) as friend from Children
) i
where i.friend->>'name' like '%Ra');
DBFiddle

Json query vs SQL query using JSON in Oracle 12c (Performance)

I am using oracle 12c and Sql Developer with json
For this example I have the follow JSON:
{
"id": "12",
"name": "zhelon"
}
So I have created the follow table for this:
create table persons
id number primary key,
person clob,
constraint person check(person is JSON);
The idea is persist in person column the previous JSON and use a the follow query to get that data
SELECT p.person FROM persons p WHERE json_textvalue('$name', 'zhelon')
Talking about perfonce, I am intresting to extract some json field and add new a colum to the table to improve the response time (I don't know if that is possible)
create table persons
id number primary key,
name varchar(2000),
person clob,
constraint person check(person is JSON);
To do this:
SELECT p.person FROM persons p WHERE p.name = 'zhelon';
My question is:
What's the best way to make a query to get data? I want to reduce the response time.
Which query get the data faster ?
SELECT p.person FROM persons p WHERE json_textvalue('$name', 'zhelon')
or
SELECT p.person FROM persons p WHERE p.name = 'zhelon';
You can create a virtual column like this:
ALTER TABLE persons ADD (NAME VARCHAR2(100)
GENERATED ALWAYS AS (JSON_VALUE(person, '$name' returning VARCHAR2)) VIRTUAL);
I don't know the correct syntax of JSON_VALUE but I think you get an idea.
If needed you can also define a index on such columns like any other column.
However, when you run SELECT p.person FROM persons p WHERE p.name = 'zhelon';
I don't know which value takes precedence, p.person from JSON or the column.
Better use a different name in order to be on the safe side:
ALTER TABLE persons ADD (NAME_VAL VARCHAR2(100)
GENERATED ALWAYS AS (JSON_VALUE(person, '$name' returning VARCHAR2)) VIRTUAL);
SELECT p.person FROM persons p WHERE p.NAME_VAL= 'zhelon';

How to join on to variable table based on field value?

I have a table called tracks with with basic data. The important parts are that this table has a column named id and event. The value of the event field is the name of another table. That table has a matching id with a lot of details about what was tracked. Is it possible to do something like this?
SELECT id, event, e.*
FROM tracks t
LEFT JOIN $event e ON t.id = e.id
The value of event could be one of a hundred different values.
Probably you could use inheritance: PostgreSQL 9.5.1 Documentation: Inheritance
In this case you may have empty parent table:
CREATE TABLE events(
id SERIAL PRIMARY KEY,
event_type INTEGER,
...
);
And bunch of children tables
CREATE TABLE events_1(event_type INTEGER DEFAULT 1 CHECK(event_type = 1)) INHERITS (events);
CREATE TABLE events_2(event_type INTEGER DEFAULT 2 CHECK(event_type = 2)) INHERITS (events);
...
Then you will be able to use queries like:
SELECT t.id, t.event_type, e.*
FROM tracks t
JOIN events e on t.id = e.id AND t.event_type = e.event_type;
But you have to add all columns to parent if you want request them from parent table.
UPD: you cannot use variable as table name in pure sql. Only way to do it is dynamic code generation (for example in plpgsql).
You can't have a variable table name in a simple SQL query; one way or another, you need to build and execute a dynamic query string.
If you want to avoid doing this in your application code, you'll need to use PL/pgSQL's EXECUTE, which means you'll have to create a function to do it.
If the common fields in your event tables are e.g. x INT, y INT, then this should work (though it may not be particularly efficient):
CREATE FUNCTION EventTable(TableName TEXT, id INT) RETURNS TABLE (x INT, y INT) AS
$$
BEGIN
RETURN QUERY EXECUTE 'SELECT x, y FROM ' || TableName || ' WHERE id = $1' USING id;
END
$$
LANGUAGE plpgsql;
SELECT id, event, e.*
FROM t
LEFT JOIN EventTable(event, id) e ON true;
SQLFiddle example

how to transform vertical fields in a table to horizontal result by SQL

I have a table like this:
create table t1 {
person_id int,
item_name varchar(30),
item_value varchar(100)
};
Suppose person_id+item_name is the composite key, now I have some data (5 records) in table t1 as below:
person_id ====item_name ====== item_value
1 'NAME' 'john'
1 'GENDER' 'M'
1 'DOB' '1970/02/01'
1 'M_PHONE' '1234567890'
1 'ADDRESS' 'Some Addresses unknown'
Now I want to use SQL (or combing store procedure/function or whatever) to query the above result (1 result set) become:
NAME==GENDER==DOB========M_PHONE=======ADDRESS===============
1 M 1970/02/01 1234567890 Some Addresses unknown
How should I do ?
Thank you for your help.
Regardless of the database you are using, the concept of what you are trying to achieve is called "Pivot Table".
Here's an example for mysql:
http://en.wikibooks.org/wiki/MySQL/Pivot_table
Some databases have builtin features for that, see the links below.
SQLServer:
http://msdn.microsoft.com/de-de/library/ms177410.aspx
Oracle:
http://www.dba-oracle.com/t_pivot_examples.htm
You can always create a pivot by hand. Just select all the aggregations in a result set and then select from that result set. Note, in your case, you can put all the names into one column using concat (i think that's group_concat in mysql), since you cannot know how many names are related to a person_id.
Finally, I found the solution in PostgreSQL:
select * from crosstab ('select person_id, item_name, item_value from t1 where person_id = 1 ')
as virtual_table ( person_id integer, name varchar, gender varchar, dob varchar, m_phone varchar, address varchar)
Also need to install the crosstab function on Postgres. See more: http://www.postgresql.org/docs/8.3/static/tablefunc.html