Я бы хотел динамически запрашивать данные, которые представлены в виде длинной строки, определяя, как читать строку и как ее разбивать.
Таким образом, я могу определить данные со следующими элементами
FIELD_NAME VARCHAR2(30) NOT NULL,
DATA_TYPE VARCHAR2(20) NOT NULL,
COLUMN_ID NUMBER NOT NULL,
FIELD_START_POS NUMBER,
FIELD_END_POS NUMBER,
FIELD_LEN NUMBER,
ROW_TYPE VARCHAR2(10),
DATE_MASK VARCHAR2(12)
пример данных в этой таблице
Могу ли я использовать эту информацию для создания выбора, который будет выглядеть примерно как
SELECT CASE cd.data_type
WHEN 'DATE'
THEN
TO_DATE (SUBSTR (sd.source_text, cd.field_start_pos, cd.field_len), cd.date_mask)
WHEN 'NUMBER'
THEN
TO_NUMBER (SUBSTR (sd.source_text, cd.field_start_pos, cd.field_len))
ELSE
TRIM (SUBSTR (sd.source_text, cd.field_start_pos, cd.field_len))
END
AS cd.field_name
FROM staged_data sd, column_definitions cd
У меня возникают трудности при попытке связать 2 вместе.
Я знаю, что мог бы повернуть имена столбцов в определении следующим образом:
SELECT *
FROM column_definitions
PIVOT (max(field_name) FOR column_id IN (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20))
, но это все равно приводит кво многих строках
Моя цель состоит в том, чтобы сгенерировать этот оператор, чтобы его можно было запустить через EXECUTE IMMEDIATE, чтобы он мог работать для многих различных файлов, просто определяя, как читать строку.
У меня также есть необходимость читать разные типы строк, следовательно, столбец row_type, который будет определен для того же файла, но имел свой собственный порядок столбцов и столбцы.
Итак, я былв состоянии генерировать строку, которую я ищу, на основе метаданных о подготовленном файле, например:
DECLARE
select_items VARCHAR2 (4000);
BEGIN
FOR c IN ( SELECT *
FROM column_definitions
WHERE file_pk = 1 AND row_type = 1
ORDER BY column_id)
LOOP
IF c.data_type = 'NUMBER'
THEN
select_items :=
select_items
|| 'CASE WHEN is_number(SUBSTR(row_data,'
|| c.field_start_pos
|| ','
|| c.field_len
|| ')) = ''TRUE'' THEN TO_NUMBER(SUBSTR(row_data,'
|| c.field_start_pos
|| ','
|| c.field_len
|| ')) ELSE NULL END AS '
|| c.field_name
|| ',';
ELSIF c.data_type = 'DATE'
THEN
select_items :=
select_items
|| 'CASE WHEN ISDATE(SUBSTR(row_data,'
|| c.field_start_pos
|| ','
|| c.field_len
|| '))=''true'' THEN TO_DATE(SUBSTR(row_data,'
|| c.field_start_pos
|| ','
|| c.field_len
|| '),'''
|| c.date_mask
|| ''') ELSE NULL END AS '
|| c.field_name
|| ',';
ELSE
select_items :=
select_items
|| 'TRIM(SUBSTR(row_data,'
|| c.field_start_pos
|| ','
|| c.field_len
|| ')) AS '
|| c.field_name
|| ',';
END IF;
END LOOP;
select_items := SUBSTR (select_items, 1, LENGTH (select_items) - 1);
select_items :=
'SELECT '
|| select_items
|| ' FROM STAGED_FILE where row_type=1 AND rownum <= 1000;';
DBMS_OUTPUT.PUT_LINE (select_items);
END;
, это выдает что-то вроде этого:
SELECT CASE
WHEN is_number (SUBSTR (row_data, 1, 1)) = 'TRUE'
THEN
TO_NUMBER (SUBSTR (row_data, 1, 1))
ELSE
NULL
END
AS REC_TYPE_IND,
SUBSTR (row_data, 11, 4) AS SRVC_LOC,
CASE
WHEN ISDATE (SUBSTR (row_data, 15, 8)) = 'true'
THEN
TO_DATE (SUBSTR (row_data, 15, 8), 'YYYYMMDD')
ELSE
NULL
END
AS BEGIN_DT,
CASE
WHEN ISDATE (SUBSTR (row_data, 23, 8)) = 'true'
THEN
TO_DATE (SUBSTR (row_data, 23, 8), 'YYYYMMDD')
ELSE
NULL
END
AS END_DT,
SUBSTR (row_data, 31, 50) AS ID,
SUBSTR (row_data, 101, 2) AS COUNTY_CD,
SUBSTR (row_data, 103, 30) AS ADDR_LN_1,
SUBSTR (row_data, 133, 30) AS ADDR_LN_2,
SUBSTR (row_data, 163, 18) AS CITY,
SUBSTR (row_data, 181, 2) AS STATE_CD,
CASE
WHEN is_number (SUBSTR (row_data, 183, 5)) = 'TRUE'
THEN
TO_NUMBER (SUBSTR (row_data, 183, 5))
ELSE
NULL
END
AS ZIP_CD,
CASE
WHEN is_number (SUBSTR (row_data, 188, 4)) = 'TRUE'
THEN
TO_NUMBER (SUBSTR (row_data, 188, 4))
ELSE
NULL
END
AS ZIP_CD4,
CASE
WHEN is_number (SUBSTR (row_data, 192, 10)) = 'TRUE'
THEN
TO_NUMBER (SUBSTR (row_data, 192, 10))
ELSE
NULL
END
AS PHONE_NUM
FROM staged_FILE
WHERE row_type = 1 AND ROWNUM <= 1000;
Сейчасчтобы решить, как динамически создавать ассоциативный массив для вставки данных или другой способ работы с данными.