В 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;