2

I want to change the condition on the array column call_type in below query so it excludes everything that has 'visit_occurred'.
How do I work with that array part?

select staff_id,
   COUNT(event_id) as offered
from call_logs as logs
where visit_offered
and contact_date between now() - interval '1 weeks' and now()
and provider_type = 'Contractor'
and contact_with != 'company_staff'
and direction = 'outbound'
and outcome = 'Successful'
and call_type && array  ['Schedule','schedule_visit']
group by staff_id;
Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
  • *"excludes everything that has 'visit_occurred'"* is a bit fuzzy. Do you want to match array elements *exactly* or identify elements that *contain* the given string? And please *always* disclose your version of Postgres. – Erwin Brandstetter Jun 04 '18 at 17:36

1 Answers1

4

To simply match array elements as a whole use the ARRAY contains operator @>, negated:

AND  NOT call_type @> '{schedule_visit}'::text[]

Note the array wrapper. The cast to text[] is typically not needed, but can help to avoid ambiguity.

If the column can be NULL, and you don't want to exclude such rows:

AND  (call_type @> '{schedule_visit}'::text[]) IS NOT TRUE

Can be supported with an index:

Pattern matching is more sophisticated. Use a NOT EXISTS expression:

AND NOT EXISTS (
   SELECT FROM unnest(logs.call_type) call
   WHERE  call ILIKE '%visit_occurred%'  -- case insensitive?
   )

No index support for this. Related answer for a JSON array (same principle):

An alternative would be normalizing your array column as a separate n:1 table.

Community
  • 1
  • 1
Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228