How to set an array contains value condition with Ruby Sequel? - arrays

I have this function that I need to modified to select from elements table the rows in which the column filters(array type) contain the feature_id param
def get_categories_by_company_and_feature(company_id:,feature_id:)
DB[:categories]
.where(company_id: company_id)
.join(:elements, category_id: :id)
.order(:category_name, :element_name)
.select_all(:categories, :elements)
.select_append(Sequel[:categories][:user_active].as(:category_user_active),
Sequel[:categories][:id].as(:category_id),
Sequel[:elements][:id].as(:element_id))
end
I've seen documentation with array_op.contains(:a) and many operators< but I don't know how to combine it with this syntax.
Also, what kind of operators can I apply for a column like Sequel[:categories][:user_active]?

Related

How can I use an array as input for FILTER function in Google Spreadsheet?

So this might be trivial, but it's kinda hard to ask. I'd like to FILTER a range based other FILTER results.
I'll try to explain from inside out (related to image below):
I use filter to find all names for given id (the results are joined in column B). This works fine and returns an array of values. This is the inner FILTER.
I want to use this array of names to find all values for them using another outer FILTER.
In other words: Find maximum value for all names for given id.
Here is what I've figured:
=MAX(FILTER(J:J, CONTAINS???(FILTER(G:G, F:F = A2), I:I)))
^--- imaginary function returning TRUE for every value in I
that is contained in the array
=MAX(FILTER(J:J, I:I = FILTER(G:G, F:F = A2)))
^--- equal does not work here when filter returns more than 1 value
=MAX(FILTER(J:J, REGEXMATCH(JOIN(",", FILTER(G:G, F:F = A2)), I:I)))
^--- this approach WORKS but is ineffective and slow on 10k+ cells
https://docs.google.com/spreadsheets/d/1k5lOUYMLebkmU7X2SLmzWGiDAVR3u3CSAF3dYZ_VnKE
I hope to find better CONTAINS function then the REGEXMATCH/JOIN combo, or to do the task using other approach.
try this in A2 cell (after you delete everything in A2:C range):
=SORTN(SORT({INDIRECT("F2:F"&COUNTA(F2:F)+1),
TRANSPOSE(SUBSTITUTE(TRIM(QUERY(QUERY(QUERY({F2:G},
"select max(Col2) group by Col2 pivot Col1"), "offset 1"),,999^99)), " ", ",")),
VLOOKUP(INDIRECT("G2:G"&COUNTA(F2:F)+1), I2:J, 2, 0)}, 1, 1, 3, 0), 999^99, 2, 1, 1)

How to use LIKE on elements of a JSONB array?

I need to search with LIKE or ILIKE - applied to elements of a JSONB[] column.
I can use unnest() to display nested JSONB elements separately, but I am having trouble combining that with my LIKE expression. My query:
SELECT
UNNEST( column_jsonb[] )
FROM
table1
WHERE
UNNEST( column_jsonb[] ) ->> 'member_type' LIKE '%member%'
Results in an error:
argument of WHERE must not return a set
How to get this right?
If it's indeed a jsonb[] column:
SELECT * -- or whatever
FROM t, unnest(jsonb_col) j
WHERE j->>'member_type' LIKE '%member%';
That's an implicit CROSS JOIN LATERAL.
If it's a JSON array in a plain jsonb column (more likely):
SELECT *
FROM t1, jsonb_array_elements(jsonb_col) j
WHERE j->>'member_type' LIKE '%member%';
Related:
Query for array elements inside JSON type

Access the index of an element in a jsonb array

I would like to access the index of an element in a jsonb array, like this:
SELECT
jsonb_array_elements(data->'Steps') AS Step,
INDEX_OF_STEP
FROM my_process
I don't see any function in the manual for this.
Is this somehow possible?
Use with ordinality. You have to call the function in the from clause to do this:
with my_process(data) as (
values
('{"Steps": ["first", "second"]}'::jsonb)
)
select value as step, ordinality- 1 as index
from my_process
cross join jsonb_array_elements(data->'Steps') with ordinality
step | index
----------+-------
"first" | 0
"second" | 1
(2 rows)
Read in the documentation (7.2.1.4. Table Functions):
If the WITH ORDINALITY clause is specified, an additional column of type bigint will be added to the function result columns. This column numbers the rows of the function result set, starting from 1.
You could try using
jsonb_each_text(jsonb)
which should supply both the key and value.
There is an example in this question:
Extract key, value from json objects in Postgres
except you would use the jsonb version.

Make a new array with items derived from another array

Given a PostgreSQL ARRAY of items of one type, how can I create a new array where each item is derived from the items in the initial array?
Example: I have an array of INTERVAL values. I want a new array where each item is a NUMERIC(10, 1) that is the total number of seconds in the corresponding INTERVAL value.
I know how to convert one INTERVAL value:
foo=> SELECT '00:01:20.000'::INTERVAL AS duration_interval;
duration_interval
-------------------
00:01:20
(1 row)
foo=> SELECT extract(EPOCH FROM date_trunc('second', '00:01:20.000'::INTERVAL))
::NUMERIC(10, 1) AS duration_seconds;
duration_seconds
------------------
80.0
(1 row)
The array does not exist in a table – this is a value returned from another function call – so the conversion code needs to operate on it as an array.
How can I convert an array of INTERVAL values to an array of corresponding NUMERIC values?
You need to unnest() the array, do the conversion and then aggregate back into an array.
Assuming you want to do this on a real table with a primary key:
SELECT pk, array_agg(extract(epoch from dur_int)::numeric(10,1)
ORDER BY ordinality) AS duration_seconds
FROM my_table, unnest(duration_interval) WITH ORDINALITY d(dur_int)
GROUP BY pk;
If you have a single array, such as the result from a function call:
SELECT array_agg(extract(epoch from dur_int)::numeric(10,1)
ORDER BY ordinality) AS duration_seconds
FROM unnest(function(...)) WITH ORDINALITY d(dur_int);
Note that you need the WITH ORDINALITY clause when unnesting the array. This will add a column ordinality to the result such that every row has two columns: (dur_int interval, ordinality bigint). When putting the array back again with seconds instead of an interval, you order the rows by the ordinality column. That way you ensure that the order in the resulting array of seconds is the same as in the original array of intervals. (In general, SQL row sources have no specific ordering, the server may present rows in any order it prefers.)
If you have access to the function and you are not breaking other uses of it, you might be better off by changing the function such that you can use its result directly.
If there is a primary key then #Patrick answer is enough. If not then use row_number to aggregate on:
with i(i) as (values
(array['00:01:20.000','00:00:30.000']::interval[]),
(array['00:02:10.000','00:01:30.000']::interval[])
)
select array_agg(extract(epoch from a)::numeric(10,1))
from (
select i, row_number() over() as r
from i
) s, unnest(i) a (a)
group by r
;
array_agg
--------------
{80.0,30.0}
{130.0,90.0}

How to determine if a particular value is in an array stored in a postgresql field

I have the following postgresql table (named "paperwork"):
paperwork_guid name primary_attribute alter_attributes
123456 test {1,2,3,4,5} {9,8,7,6}
09876 test2 {1,2,3,4} {9,8,7,6}
I would like to return the paperwork_guid for those rows having '5' in the primary_attribute array (In the above table, the result would be '123456').
If there is another question out there on this topic, I have been unable to find it.
Perhaps something along these lines:
SELECT paperwork_guid
FROM (SELECT paperwork_guid, unnest(primary_attribute) AS attr
FROM paperwork) x
WHERE attr = 5
with a DISTINCT if an attribute can occur more than once within a primary_attribute array.
A much simpler one:
SELECT paperwork_guid FROM paperwork where primary_attribute IN ('5');

Resources