PostgreSQL에서 JSONB 쿼리


14

persons두 개의 열과 idJSONB 기반 data열 을 포함 하는 테이블 이 있습니다 (이 테이블은 PostgreSQL의 JSON 지원으로 데모하기 위해 만들어졌습니다).

이제 두 개의 레코드가 있다고 가정합니다.

1, { name: 'John', age: 30 }
2, { name: 'Jane', age: 20 }

이제 25 세 이상인 모든 사람의 이름을 얻고 싶습니다.

select data->'name' as name from persons where data->'age' > 25

불행히도 이로 인해 오류가 발생합니다. ->>대신을 사용하여 해결할 수 ->있지만 숫자가 비교되지 않고 문자열로 표현되기 때문에 비교가 더 이상 예상대로 작동하지 않습니다.

select data->'name' as name from persons where data->>'age' > '25'

그런 다음을 사용하여 실제로 문제를 해결할 수 있다는 것을 알았 ->습니다 int.

select data->'name' as name from persons where cast(data->'age' as int) > 25

이것은 작동하지만 실제 유형을 알아야한다는 것은 좋지 않습니다 ( ageJSON 문서 의 유형 은 number어쨌든 PostgreSQL이 스스로 알아낼 수없는 이유는 무엇입니까?).

그런 다음 구문 을 text사용하여 수동으로 변환하면 ::모든 것이 예상대로 작동 한다는 것을 알았 습니다. 이제 문자열을 다시 비교하고 있습니다.

select data->'name' as name from persons where data->'age'::text > '25'

그런 다음 나이 대신 이름으로 시도하면 작동하지 않습니다.

select data->'name' as name from persons where data->'name'::text > 'Jenny'

오류가 발생합니다.

json 유형의 유효하지 않은 입력 구문

분명히, 나는 여기에 무언가를 얻지 못한다. 불행히도 PostgreSQL에서 JSON을 사용하는 실제 사례를 찾기는 매우 어렵습니다.

힌트가 있습니까?


1
에서가 data->'name'::text, 당신은 캐스팅 'name'텍스트 문자열이 아닌 결과를. 유효한 JSON 리터럴 '25'이므로 비교할 때 오류가 발생하지 않습니다 25. 그러나 Jenny( 그렇지 는 않지만 ) 아닙니다 "Jenny".
chirlu

고마워, 그것은 해결책이다 :-). 나는와 혼동 'Jenny'했다 '"Jenny"'.
Golo Roden

답변:


15

jsonb값을 에 캐스팅하려고하므로 작동하지 않습니다 integer.

select data->'name' as name from persons where cast(data->'age' as int) > 25

이것은 실제로 작동합니다 :

SELECT data->'name' AS name FROM persons WHERE cast(data->>'age' AS int) > 25;

또는 더 짧게 :

SELECT data->'name' AS name FROM persons WHERE (data->>'age')::int > 25;

이:

SELECT data->'name' AS name FROM persons WHERE data->>'name' > 'Jenny';

두 혼동 것 같다 사업자 ->->>연산자 우선 순위 . 캐스트 ::는 json (b) 연산자보다 더 강력하게 바인딩됩니다.

동적으로 유형 파악

이것은 귀하의 질문에서 더 흥미로운 부분입니다.

JSON 문서의 연령 유형은 어쨌든 숫자이므로 PostgreSQL이 그 자체를 알아낼 수없는 이유는 무엇입니까?

SQL은 엄격하게 형식화 된 언어이므로 동일한식이 integer한 행 text에서 다음 행 으로 평가되는 것을 허용하지 않습니다 . 그러나 boolean테스트 결과 에만 관심이 있으므로 다음 결과에 CASE따라 분기 되는 표현식 으로이 제한 사항을 해결할 수 있습니다 jsonb_typeof().

SELECT data->'name'
FROM   persons
WHERE  CASE jsonb_typeof(data->'age')
        WHEN 'number'  THEN (data->>'age')::numeric > '25' -- treated as numeric
        WHEN 'string'  THEN data->>'age' > 'age_level_3'   -- treated as text
        WHEN 'boolean' THEN (data->>'age')::bool           -- use boolean directly (example)
        ELSE FALSE                                         -- remaining: array, object, null
       END;

>연산자 의 오른쪽에있는 형식화되지 않은 문자열 리터럴 은 왼쪽에있는 해당 값 유형으로 자동 변환됩니다. 유형이 지정된 값을 거기에 넣으면 시스템에 등록 된 적절한 암시 적 캐스트가없는 한 유형이 일치하거나 명시 적으로 캐스트해야합니다.

당신이 경우 알고있는 모든 것을 숫자 값을 실제로 integer수행 할 수도 있습니다 :

... (data->>'age')::int > 25 ...

위의 select 문 비교를위한 sqlalchemy 핵심 표현식은 무엇입니까? s = select ([issues]). where (issues.c.id == mid) .select_from (issues, ..... outerjoin (issues.c.data [ 'type_id'] == mtypes.c.id) ) ... 여기 issues.c.data jsonb 데이터 타입과 정수 타입의 mtypes.c.id와 비교
user956424
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.