Можем ли мы передать параметр JSON_VALUE в Oracle

У меня есть запрос, который извлекает данные формата json из столбца. я хочу получить данные json, динамически передавая field_name из столбца.

Например

SELECT SUBJECT_MARKS
FROM STUDENT
WHERE STUDENT_ID = 101

результат:

{
    "English": "70",
    "Hindi": "80",
    "Maths": "90",
    "Science": "90",
    "Social": "85"
}

Если я хочу получить конкретные предметные оценки, то запрос будет таким:

SELECT JSON_VALUE(SUBJECT_MARKS,'$.Maths')
FROM STUDENT
WHERE STUDENT_ID = 101

Теперь результат:

90

Теперь мое требование состоит в том, чтобы динамически получать ТЕМАТИЧЕСКИЕ МАРКИ, указывая имя субъекта в качестве параметра в запросе.

SELECT JSON_VALUE(SUBJECT_MARKS,:pSubjectMarks)
FROM STUDENT
WHERE STUDENT_ID = 101

при выполнении запроса, когда мы даем :pSubjectMarks как '$.Science' то выдает сообщение об ошибке

ORA-40454: path expression not a literal 40454. 00000 - "path expression not a literal" *Cause: The provided path expression was not a literal (a constant). *Action: Provide a constant path expression. Error at Line: 29 Column: 45

Может ли кто-нибудь помочь мне найти решение для запроса заранее спасибо

Что-то не имеет смысла. Вы спрашиваете о JSON_VALUE, но вопрос конкретно помечен oracle11g и oracle10g. Функции JSON были добавлены только в Oracle 12. Итак, что есть что?

mathguy 12.05.2022 21:43

Опубликованная вами ошибка не может появиться в Oracle 11g и, более того, в древнем 10g, как указано выше. Пожалуйста, отредактируйте теги версии Oracle.

astentx 12.05.2022 22:50
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
30
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Начиная с Oracle 12 (когда была добавлена ​​поддержка функций JSON), вы можете внести в белый список все возможные параметры в выражении CASE, используя:

SELECT CASE :pSubjectMarks
       WHEN 'English' THEN JSON_VALUE(SUBJECT_MARKS,'$.English')
       WHEN 'Hindi'   THEN JSON_VALUE(SUBJECT_MARKS,'$.Hindi')
       WHEN 'Maths'   THEN JSON_VALUE(SUBJECT_MARKS,'$.Maths')
       WHEN 'Science' THEN JSON_VALUE(SUBJECT_MARKS,'$.Science')
       WHEN 'Social'  THEN JSON_VALUE(SUBJECT_MARKS,'$.Social')
       END as subject_marks
FROM   STUDENT s

или:

SELECT CASE :pSubjectMarks
       WHEN 'English' THEN english
       WHEN 'Hindi'   THEN hindi
       WHEN 'Maths'   THEN maths
       WHEN 'Science' THEN science
       WHEN 'Social'  THEN social
       END as subject_marks
FROM   STUDENT s
       CROSS APPLY JSON_TABLE(
         s.subject_marks,
         '$'
         COLUMNS (
           ENGLISH NUMBER PATH '$.English',
           HINDI   NUMBER PATH '$.Hindi',
           MATHS   NUMBER PATH '$.Maths',
           SCIENCE NUMBER PATH '$.Science',
           SOCIAL  NUMBER PATH '$.Social'
         )
       ) j
WHERE  STUDENT_ID = 101;

дб <> рабочий пример здесь

Ответ принят как подходящий

Вы можете превратить тему, из которой хотите получить информацию, в утверждение EXECUTE IMMEDIATE. Поскольку все ваши темы представляют собой простые строки, вы можете использовать пакет DBMS_ASSERT для проверки ввода параметра p_subject_name, чтобы предотвратить внедрение SQL.

Ниже приведен пример построения процедуры.

Настраивать

CREATE TABLE students
AS
    SELECT 101                                                                                        AS student_id,
              EMPTY_CLOB ()
           || '{ "English": "70", "Hindi": "80", "Maths": "90", "Science": "90", "Social": "85" }'    AS subject_marks
      FROM DUAL;
DECLARE
    PROCEDURE print_subject_score (p_student_id students.student_id%TYPE, p_subject_name VARCHAR2)
    IS
        l_sql     VARCHAR2 (1000);
        l_score   VARCHAR2 (5);
    BEGIN
        l_sql :=
               'select json_value(subject_marks, ''$.'
            || DBMS_ASSERT.SIMPLE_SQL_NAME (p_subject_name)
            || ''') from students where student_id = :p_student_id';

        EXECUTE IMMEDIATE l_sql
            INTO l_score
            USING p_student_id;

        DBMS_OUTPUT.put_line (l_score);
    EXCEPTION
        WHEN NO_DATA_FOUND
        THEN
            --Student ID does not exist
            NULL;
    END;
BEGIN
    print_subject_score (p_student_id => 101, p_subject_name => 'English');
    print_subject_score (p_student_id => 101, p_subject_name => 'Test');
    print_subject_score (p_student_id => 102, p_subject_name => 'Maths');
END;
/

Поскольку у вас есть доступ к функции JSON_VALUE, ваша версия Oracle не ниже 12.1. Эта версия также обеспечивает доступ к локальным объявлениям PL/SQL в запросах SQL, где у вас есть полный динамический доступ к ключам JSON.

Таким образом, вы можете использовать для этого тип данных JSON_OBJECT_T. Как видите, путь передается как значение столбца (выражение, а не литерал), и вы можете использовать переменную связывания вместо выражения.

with function get_mark(
  p_marks in varchar2,
  p_subj in varchar2
)
return number
as
  json JSON_OBJECT_T;
begin
  json := JSON_OBJECT_T(p_marks);
  return json.get_String(p_subj);
end;

select
  t.column_value as subj,
  get_mark(SUBJECT_MARKS, t.column_value) as mark
from students
  cross join sys.odcivarchar2list(
    'English',
    'Hindi',
    'Maths', 
    'Science',
    'Social',
    'something'
  )  t
where student_id = 101
SUBJ      | MARK
:-------- | ---:
English   |   70
Hindi     |   80
Maths     |   90
Science   |   90
Social    |   85
something | null

дб <> рабочий пример здесь

Другие вопросы по теме