Как я могу установить максимальное значение, используя список агг - PullRequest
0 голосов
/ 28 октября 2018

Я прочитал другие вопросы и ответы, и они не помогают с моей проблемой.Я спрашиваю, есть ли способ установить ограничение на количество результатов, возвращаемых в listagg.

Я использую этот запрос

HR - Любой ребенок с ЧСС <80 AS </p>

SELECT fm.y_inpatient_dat, h.pat_id, h.pat_enc_csn_id, 
LISTAGG(meas_value, '; ') WITHIN GROUP (ORDER BY fm.recorded_time) 
abnormal_HR_values
from
ip_flwsht_meas fm
join pat_enc_hsp h on fm.y_inpatient_dat = h.inpatient_data_id
where fm.flo_meas_id in ('8' ) and (to_number(MEAS_VALUE) <80)
AND fm.recorded_time between (select start_date from dd) AND (select end_date from dd)
group by fm.y_inpatient_dat,h.pat_id, h.pat_enc_csn_id)

, и я получаю следующую ошибку:

ORA-01489: результат конкатенации строк слишком длинный

Я изучал онлайн, как установить ограничение размера, но я не могу заставить его работать.Может кто-нибудь посоветуете, пожалуйста, как установить ограничение, чтобы оно не превышало 50 символов.

1 Ответ

0 голосов
/ 28 октября 2018

В Oracle 12.2 вы можете использовать ON OVERFLOW ERROR в LISTAGG, например:

LISTAGG(meas_value, '; ' ON OVERFLOW ERROR) WITHIN GROUP (ORDER BY fm.recorded_time) 

Затем вы можете окружить это SUBSTR(), чтобы получить первые 50 символов.

До 12.2 вам нужно реструктурировать запрос, чтобы ограничить количество строк, которые видят LISTAGG.Вот пример того, что использует DBA_OBJECTS (так что люди без ваших таблиц могут запустить его).Это будет только первые три значения для каждого типа объекта.

SELECT object_type, 
       listagg(object_name, ', ') within group ( order by object_name) first_three
FROM (
    SELECT object_type, 
           object_name, 
           row_number() over ( partition by object_type order by object_name ) ord
    FROM   dba_objects
    WHERE  owner = 'SYS'
    )
WHERE ord <= 3
GROUP BY object_type
ORDER BY object_type;

Идея состоит в том, чтобы нумеровать строку, которую вы хотите агрегировать, а затем агрегировать только первые X из них, где «X» достаточно малоне превышать максимальную длину на VARCHAR2.«X» будет зависеть от ваших данных.

Или, если вы не хотите, чтобы усечение с 50 символами происходило со средними значениями, и / или вы не знаете, сколько значений безопасно разрешить, выможете заменить выражение ord на выражение running_length, чтобы сохранить счетчик длины и ограничить его до того, как оно достигнет вашего предела (из 50 символов).Это выражение будет SUM(length()) OVER (...).Вот так:

SELECT object_type, 
       listagg(object_name, ', ') within group ( order by object_name) first_50_char,
FROM (
    SELECT object_type, 
           object_name, 
           sum(length(object_name || ', ')) 
              over ( partition by object_type order by object_name ) running_len
    FROM   dba_objects
    WHERE  owner = 'SYS'
    )
WHERE running_len <= 50+2  -- +2 because the last one won't have a trailing delimiter
GROUP BY object_type
ORDER BY object_type;

С вашим запросом все, что собрано, будет выглядеть так:

SELECT  y_inpatient_dat,
        pat_id,
        pat_enc_csn_id,
        LISTAGG(meas_value, '; ') WITHIN GROUP ( ORDER BY fm.recorded_time ) abnormal_HR_values
FROM (
    SELECT fm.y_inpatient_dat, 
           h.pat_id, 
           h.pat_enc_csn_id, 
           meas_value,
           fm.recorded_time,
           SUM(length(meas_value || '; ') OVER ( ORDER BY fm.recorded_time ) running_len
    FROM   ip_flwsht_meas fm
    INNER JOIN pat_enc_hsp h on fm.y_inpatient_dat = h.inpatient_data_id
    WHERE  fm.flo_meas_id in ('8' ) and (to_number(MEAS_VALUE) <80)
    AND    fm.recorded_time BETWEEN 
             (SELECT start_date FROM dd) AND (SELECT end_date FROM dd)
)
WHERE running_len <= 50+2
GROUP BY fm.y_inpatient_dat,h.pat_id, h.pat_enc_csn_id;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...