Reputation: 655
I created a postgres function that receives an array of text as parameter. For each text in the array I want to check if any of the the columns in the query match it with like clause.
Is it possible to aggregate where clause like this in a for loop?
For example for clarification, I have the above tables:
lessons
+----+-----------+-----------------+
| id | name | teacher_id |
+----+-----------+-----------------+
| 1 | English | 1 |
+----+-----------+-----------------+
| 2 | Spanish | 2 |
+----+-----------+-----------------+
Teachers
+----+-----------+
| id | name |
+----+-----------+
| 1 | Teacher 1 |
+----+-----------+
| 2 | Teacher 2 |
+----+-----------+
I want to get as parameters text[] and for each text in the array I want to execute an OR clause between the column in both tables and return array of jsons([{"id": 1, "teacher": {"id":1, "name": "Teacher1"}}]
)
For example if the parameters are ["lish", "er"] I want it to execute:
where
lessons.name like '%lish%' or teachers.name like '%lish%'
and
lessons.name like '%er%' or teachers.name like '%er%'
teacher with id 1 will return.
The thing is I don't know in advance the parameters so this is why I assume I need a FOR loop.
Also, how to I make the query to return an array of jsons that each teacher will be an inner json object of each lesson?
Would appreciate some examples if so. Thank you!
Upvotes: 0
Views: 314
Reputation: 7065
You don't need a loop-like function such as in plpgsql to get your expected result. A basic sql
query will be more efficient :
SELECT l.id, l.name, t.id, t.name
FROM lessons AS l
INNER JOIN teachers AS t
ON t.id = l.teacher_id
INNER JOIN unnest( array['lish', 'er']) AS c(cond)
ON t.name ~ c.cond OR l.name ~ c.cond
GROUP BY l.id, l.name, t.id, t.name
HAVING count(*) = array_length(array['lish','er'], 1)
lessons
and teachers
with a
match on teacher_id
.unnest
function.lessons
and teachers
, both names are compared to the input array element using the regular expression ~
operator.HAVING
clause where count(*)
is the number of resulting
rows for the same (lessons.id, teachers.id) tuple and it is compared
to the total number of elements in the array with the array_length
function..If you want to return an array of jsonb, just format the query result :
SELECT json_agg(c.result)
FROM (
SELECT (json_build_object('lesson_id', l.id, 'lesson_name',l.name, 'teacher', json_build_object('teacher_id', t.id, 'teacher_name', t.name))) AS result
FROM lessons AS l
INNER JOIN teachers AS t
ON t.id = l.teacher_id
INNER JOIN unnest( array['lish', 'er']) AS c(cond)
ON t.name ~ c.cond OR l.name ~ c.cond
GROUP BY l.id, l.name, t.id, t.name
HAVING count(*) = array_length(array['lish','er'], 1)) AS c
see the full test result in dbfiddle
Upvotes: 1