How to get data from brackets in PostgreSQL? - postgresql

I have a table (that shape I can't control) where I have one column in data type varchar(500), but strings are in the brackets.
Can I get data from these brackets in another way than this?
select *
from my_table
where products LIKE '%c%'
;
I tried to change data type for array, json, jsonb - but it doesn't work.
"Products" are always in the same order, but not every user has all of them and some have nothing.

Related

postgresql 11 select value from jsonb data by path from other table field

I have jsonb field 'data' in my table. I can get value of subKey by select data#>'{key1,subKey}' from table.How to insert a path into select if the path is stored in another table as a string 'key1,subKey'?
You should really store it as an array, not as a string, since that is how it will be used. You can just split it to an array dynamically, but then what if you ever need the comma to appear literally in the path?
with t as (select '{"key1":{"subKey":"foo"}}'::jsonb as data),
k as (select 'key1,subKey' as k)
select data#>regexp_split_to_array(k,',') from t,k;

How to create a column that holds an array in Postgres?

Background:
I am making a db for a reservartions calendar. The reservations are hourly based, so I need to insert many items to one column called "hours_reserved".
Example tables of what I need:
Table "Space"
Column / Values
id / 1
date / 5.2.2020
hours / { 8-10, 10-12 }
Table "reservation"
Column / Values
id / 1
space_id / 1
date / 5.2.2020
reserved_hours / 8-10
Table "reservation"
Column / Values
id / 2
space_id / 1
date / 5.2.2020
hours / 10-12
So I need to have multiple items inserted into "space" table "hours" column.
How do I do this in Postgres?
Also is there a better way to accomplish this?
There is more way to do this, depending on the type of the hours field (i.e. text[], json or jsonb) I'd go with jsonb just because you can do a lot of things with it and you'll find this experience to be useful in the short term.
CREATE TABLE "public"."space"
("id" SERIAL, "date_schedule" date, "hours" jsonb, PRIMARY KEY ("id"))
Whenever you insert a record in this table that's manually crafted, write it as text (single quoted json object) and cast it to jsonb
insert into "space"
(date_schedule,hours)
values
('05-02-2020'::date, '["8-10", "10-12"]'::jsonb);
There is more than one way to match these available hours against the reservations and you can take a look at the docs, on the json and jsonb operations. For example, doing:
SELECT id,date_schedule, jsonb_array_elements(hours) hours FROM "public"."space"
would yield
Which has these ugly double quotes (which is correct, since json can hold several kinds of scalars, that column is polimorfic :D)
However, you can perform a little transformation to remove them and be able to perform a join with reservations
with unnested as (
SELECT id,date_schedule, jsonb_array_elements(hours) hours FROM "public"."space"
)
select id,date_schedule,replace(hours::text, '"','') from unnested
The same can be achieved defining the field as text[] (the insertion syntax is different but trivial)
in that scenario your data will look like:
Which you can unwrap as:
SELECT id,date_schedule, unnest(hours) FROM "public"."space"
Apparently
ALTER TABLE mytable
ADD COLUMN myarray text[];
Works fine.
I got a following problem when trying to put(update) into that column using postman(create works fine):
{
"myarray": ["8-10"]
}
Results into:
"message": "error: invalid input syntax for type integer:
\"{\"myarray\":[\"8-10\"]}\""

Postgres: insert value from another table as part of multi-row insert?

I am working in Postgres 9.6 and would like to insert multiple rows in a single query, using an INSERT INTO query.
I would also like, as one of the values inserted, to select a value from another table.
This is what I've tried:
insert into store_properties (property, store_id)
values
('ice cream', select id from store where postcode='SW1A 1AA'),
('petrol', select id from store where postcode='EC1N 2RN')
;
But I get a syntax error at the first select. What am I doing wrong?
Note that the value is determined per row, i.e. I'm not straightforwardly copying over values from another table.
demo:db<>fiddle
insert into store_properties (property, store_id)
values
('ice cream', (select id from store where postcode='SW1A 1AA')),
('petrol', (select id from store where property='EC1N 2RN'))
There were some missing braces. Each data set has to be surrounded by braces and the SELECT statements as well.
I don't know your table structure but maybe there is another error: The first data set is filtered by a postcode column, the second one by a property column...

HSTORE order by key/value where the value is a string representation of an integer

I'm working with an existing database and have an hstore column with the contents being a key pointing to an integer stored as a string.
I'm working with code that attempts to sort by that value but unfortunately, since it's a string, I get the unsurprising behavior that "10" comes before "2". I do not have license to change the data in the table, so I'm looking for a way to write the order so that it orders by the value as an integer rather than as the string it naturally is.
Here is some toy SQL to hopefully better show what I'm asking:
INSERT INTO hstore_test (sale)
VALUES ('"milk"=>"4",
"bread"=>"2",
"bananas"=>"12",
"cereal"=>"1"');
Now at this point I want to get all the things, sorted by milk -> value:
SELECT * FROM hstore_test ORDER BY sale -> 'milk';
This unfortunately sorts by the string value of milk ("4" in the example above).
I've been kind of envisioning something like
SELECT * FROM hstore_test ORDER BY CAST(sale -> 'milk' as INT);
but I can't convince myself that's correct.

How to combine DISTINCT and ORDER BY in array_agg of jsonb values in postgresSQL

Note: I am using the latest version of Postgres (9.4)
I am trying to write a query which does a simple join of 2 tables, and groups by the primary key of the first table, and does an array_agg of several fields in the 2nd table which I want returned as an object. The array needs to be sorted by a combination of 2 fields in the json objects, and also uniquified.
So far, I have come up with the following:
SELECT
zoo.id,
ARRAY_AGG(
DISTINCT ROW_TO_JSON((
SELECT x
FROM (
SELECT animals.type, animals.name
) x
))::JSONB
-- ORDER BY animals.type, animals.name
)
FROM zoo
JOIN animals ON animals.zooId = zoo.id
GROUP BY zoo.id;
This results in one row for each zoo, with a an aggregate array of jsonb objects, one for each animal, uniquely.
However, I can't seem to figure out how to also sort this by the parameters in the commented out part of the code.
If I take out the distinct, I can ORDER BY original fields, which works great, but then I have duplicates.
If you use row_to_json() you will lose the column names unless you put in a row that is typed. If you "manually" build the jsonb object with json_build_object() using explicit names then you get them back:
SELECT zoo.id, array_agg(za.jb) AS animals
FROM zoo
JOIN (
SELECT DISTINCT ON (zooId, "type", "name")
zooId, json_build_object('animal_type', "type", 'animal_name', "name")::jsonb AS jb
FROM animals
ORDER BY zooId, jb->>'animal_type', jb->>'animal_name'
-- ORDER BY zooId, "type", "name" is far more efficient
) AS za ON za.zooId = zoo.id
GROUP BY zoo.id;
You can ORDER BY the elements of a jsonb object, as shown above, but (as far as I know) you cannot use DISTINCT on a jsonb object. In your case this would be rather inefficient anyway (first building all the jsonb objects, then throwing out duplicates) and at the aggregate level it is plain impossible with standard SQL. You can achieve the same result, however, by applying the DISTINCT clause before building the jsonb object.
Also, avoid use of SQL key words like "type" and standard data types like "name" as column names. Both are non-reserved keywords so you can use them in their proper contexts, but practically speaking your commands could get really confusing. You could, for instance, have a schema, with a table, a column in that table, and a data type each called "type" and then you could get this:
SELECT type::type FROM type.type WHERE type = something;
While PostgreSQL will graciously accept this, it is plain confusing at best and prone to error in all sorts of more complex situations. You can get a long way by double-quoting any key words, but they are best just avoided as identifiers.