I have a department table that has a jsonb field that give the hours of operation that looks like:
{
"Friday": {
"closeTime": "1970-01-01T17:00:00.000Z",
"isOpen": true,
"isOpen24Hours": false,
"openTime": "1970-01-01T08:00:00.000Z"
},
"Monday": {
"isOpen": false
},
"Saturday": {
"isOpen": false
},
"Sunday": {
"isOpen": false
},
"Thursday": {
"closeTime": "1970-01-01T17:00:00.000Z",
"isOpen": true,
"isOpen24Hours": false,
"openTime": "1970-01-01T08:00:00.000Z"
},
"Tuesday": {
"closeTime": "1970-01-01T17:00:00.000Z",
"isOpen": true,
"isOpen24Hours": false,
"openTime": "1970-01-01T08:00:00.000Z"
},
"Wednesday": {
"closeTime": "1970-01-01T17:00:00.000Z",
"isOpen": true,
"isOpen24Hours": false,
"openTime": "1970-01-01T08:00:00.000Z"
}
}
I have another table that associates some activity on a day with a department and I want to know if on the day that the activity happened is the department was open. So how do I query this jsonb field with the day of week of the date from the other table?
I have tried something like:
select a.activity_date, a.department_id,
d.hours_of_operation->to_char(a.activity_date, 'Day')->>'isOpen' as isOpen
from activity a
join department d on a.department_id = d.id
but that only returns an isOpen value when the activity_date is a Wednesday (which is the last key in the hours_of_operation jsonb)
You probably overlooked blank-padding that comes with Day
template:
DAY
full upper case day name (blank-padded to 9 chars)
Day
full capitalized day name (blank-padded to 9 chars)
day
full lower case day name (blank-padded to 9 chars)
Which means only Wednesday
doesn't get any spaces, because it's 9 chars long already. The rest end up as keys that don't match what's in your jsonb structure, because of the additional whitespace characters. The ->
returns null
in that case. Demo at db<>fiddle:
select quote_literal(to_char(a.activity_date, 'Day'))
,a.activity_date
,a.department_id
,(d.hours_of_operation->to_char(a.activity_date, 'Day'))->>'isOpen' as isOpen
from activity a
join department d on a.department_id = d.id
quote_literal | activity_date | department_id | isopen |
---|---|---|---|
'Wednesday' |
2024-04-24 | 1 | true |
'Tuesday ' |
2024-04-23 | 1 | null |
'Monday ' |
2024-04-22 | 1 | null |
'Sunday ' |
2024-04-21 | 1 | null |
'Saturday ' |
2024-04-20 | 1 | null |
'Friday ' |
2024-04-19 | 1 | null |
'Thursday ' |
2024-04-18 | 1 | null |
'Wednesday' |
2024-04-17 | 1 | true |
Add a trim()
and it'll be fine:
select quote_literal(trim(to_char(a.activity_date, 'Day')))
,a.activity_date
,a.department_id
,(d.hours_of_operation->trim(to_char(a.activity_date, 'Day')))->>'isOpen' as isOpen
from activity a
join department d on a.department_id = d.id
Or add a fill mode FM
prefix in your to_char()
template:
Modifier Description Example FM prefix fill mode (suppress trailing zeroes and padding blanks) FM99.99
select quote_literal(to_char(a.activity_date, 'FMDay'))
,a.activity_date
,a.department_id
,(d.hours_of_operation->to_char(a.activity_date, 'FMDay'))->>'isOpen' as isOpen
from activity a
join department d on a.department_id = d.id
quote_literal | activity_date | department_id | isopen |
---|---|---|---|
'Wednesday' |
2024-04-24 | 1 | true |
'Tuesday' |
2024-04-23 | 1 | true |
'Monday' |
2024-04-22 | 1 | false |
'Sunday' |
2024-04-21 | 1 | false |
'Saturday' |
2024-04-20 | 1 | false |
'Friday' |
2024-04-19 | 1 | true |
'Thursday' |
2024-04-18 | 1 | true |
'Wednesday' |
2024-04-17 | 1 | true |