Как выровнять файл текстового формата пары значений ключа табуляции в таблице, где ключ - это столбец, а значение - это данные для ячейки - PullRequest
0 голосов
/ 14 июня 2019

У меня есть текстовый файл, в котором 1 строка разбита на несколько строк в паре ключ-значение. Данные выглядят так:

1,800001348

2, ИДЕАЛЬНЫЙ ВАРИАНТ

27, место обслуживания

39, ИДЕАЛЬНЫЙ ВАРИАНТ

400,123 ОСНОВНАЯ УЛИЦА

400, Ste G

410, СИЭТЛ

420, Вашингтон

423, BENTON

430,99336

и весь блок повторяется снова: 1,850000900

2, INVITAE CORPORATION

27, место обслуживания

39, INVITAE CORPORATION

400, XYZ 1-й ПРОСПЕКТ

410, САН-ФРАНЦИСКО

420, California

423, САН-ФРАНЦИСКО

430,94103

Я загрузил этот файл в Oracle, используя SQL Loader. Целостность сохраняется, так как у меня есть порядковый номер, прикрепленный ко всем строкам, так что я могу обойти таблицу построчно и сказать, где начинается и заканчивается 1-я строка.

KEY VALUE SEQNUM

1 800001348 1

2 ИДЕАЛЬНЫЙ ВАРИАНТ 2

27 Место обслуживания 3

39 ИДЕАЛЬНЫЙ ВАРИАНТ 4

400 123 ГЛАВНАЯ Улица 5

400 Ste G 6

410 KENNEWICK 7

420 Вашингтон 8

423 BENTON 9

430 99336 10

1 850000900 11

2 INVITAE CORPORATION 12

27 Место обслуживания 13

39 INVITAE CORPORATION 14

400 XYZ 1-й ПРОСПЕКТ 15

410 САН-ФРАНЦИСКО 16

420 Калифорния 17

423 САН-ФРАНЦИСКО 18

430 94103 19

select 
case when KEY = '1' then value else null end as FACILITY_ID,
case when KEY = '2' then value else null end as  Unknown_num,
case when KEY = '27' then value else null end as  TYPE_OF_LOCATION,
case when KEY = '39' then value else null end as  EXTERNAL_NAME,
case when KEY = '400' then value else null end as  ADDRESS,
case when KEY = '410' then value else null end as  CITY,
case when KEY = '420' then value else null end as  STATE,
case when KEY = '423' then value else null end as  COUNTY,
case when KEY = '430' then value else null end as  ZIP_CODE,
value,
SEQNUM from MDM_ODS.EAF_EPIC_IMPORT order by SEQNUM;

Я получаю транспонированный результат, но, как и ожидалось, все они находятся в разных строках и имеют много нулей, есть ли способ объединить их, чтобы сделать их в 1 строку?

FACILITY_ID UNKNOWN_NUM TYPE_OF_LOCATION EXTERNAL_NAME ADDRESS CITY 800001348
ИДЕАЛЬНЫЙ ВАРИАНТ
Место обслуживания
ИДЕАЛЬНЫЙ ВАРИАНТ
8514 Вт Gage Blvd
Ste G Кеннуик

Ответы [ 3 ]

1 голос
/ 14 июня 2019

Примерно так может работать:

SELECT facility_id, unknown_num, type_of_location, external_name,
       address, city, state, county, zip_code
   FROM (
  SELECT key,
         value facility_id,
         LEAD(value, 1)  OVER (ORDER BY seqnum) unknown_num,
         LEAD(value, 2)  OVER (ORDER BY seqnum) type_of_location,
         LEAD(value, 3)  OVER (ORDER BY seqnum) external_name,
         LEAD(value, 4)  OVER (ORDER BY seqnum) address,
         LEAD(value, 5)  OVER (ORDER BY seqnum) city,
         LEAD(value, 6)  OVER (ORDER BY seqnum) state,
         LEAD(value, 7)  OVER (ORDER BY seqnum) county,
         LEAD(value, 8)  OVER (ORDER BY seqnum) zip_code
    FROM MDM_ODS.EAF_EPIC_IMPORT
    ORDER BY seqnum)
  WHERE key=1;

LEAD(X, N) OVER (ORDER BY <sort-order>) означает возвращать значение столбца «X», которое равно «N» количеству строк перед текущей строкой со строками, упорядоченными по <sort-order>.

0 голосов
/ 14 июня 2019

Если я вас правильно понимаю, у вас есть две проблемы:

  1. Группировка пар значений по "записи" ..
  2. Поворот строк в столбцы

Я создал SQL Fiddle с такой таблицей, и я добавил ваши образцы данных.

create table your_table_t(
   k    number
  ,v    varchar2(200)
  ,seq number
);

Для первой проблемы я предположил, что key = 1 - это ваш идентификатор записи. Таким образом, цель состоит в том, чтобы назначить этот идентификатор каждой паре значений, которая принадлежит этой записи. Для этого я использовал коалесцирующее выражение, которое будет копировать значение для key = 1 на каждую пару значений.

Во второй части я просто использовал оператор Oracle PIVOT для поворота строк в столбцы.

with identify_record as(
   select k,v
            ,coalesce(    decode(k,1,v,null)
                     ,lag(decode(k,1,v,null),1) ignore nulls over(order by seq)) as id
        from your_table_t a
)
select *    
  from identify_record pivot(
         max(v) for k in(1   as FACILITY_ID
                        ,2   as Unknown_num
                        ,27  as TYPE_OF_LOCATION
                        ,39  as EXTERNAL_NAME
                        ,400 as ADDRESS
                        ,410 as CITY
                        ,420 as STATE
                        ,423 as COUNTY
                        ,430 as ZIP_CODE                        
                        )
  );

Вы получите следующий вывод:

ID          FACILITY_ID    UNKNOWN_NUM             TYPE_OF_LOCATION     EXTERNAL_NAME           ADDRESS           CITY              STATE          COUNTY            ZIP_CODE
"800001348" "800001348"    "IDEAL OPTION"          "Place of Service"   "IDEAL OPTION"          "Ste G"           "KENNEWICK"       "Washington"   "BENTON"          "99336"
"850000900" "850000900"    "INVITAE CORPORATION"   "Place of Service"   "INVITAE CORPORATION"   "XYZ 1st AVENUE"  "SAN FRANCISCO"   "California"   "SAN FRANCISCO"   "94103"
0 голосов
/ 14 июня 2019

Попробуйте следующий код:

-- MANUAL DATA CREATION
WITH DATAA AS (
    SELECT
        1 KEY,
        '800001348' VALUE,
        1 SEQNUM
    FROM
        DUAL
    UNION ALL
    SELECT
        2,
        'IDEAL OPTION',
        2
    FROM
        DUAL
    UNION ALL
    SELECT
        27,
        'Place of Service',
        3
    FROM
        DUAL
    UNION ALL
    SELECT
        39,
        'IDEAL OPTION',
        4
    FROM
        DUAL
    UNION ALL
    SELECT
        400,
        '123 MAIN STREET',
        5
    FROM
        DUAL
    UNION ALL
    SELECT
        400,
        'Ste G',
        6
    FROM
        DUAL
    UNION ALL
    SELECT
        410,
        'SEATTLE',
        7
    FROM
        DUAL
    UNION ALL
    SELECT
        420,
        'Washington',
        8
    FROM
        DUAL
    UNION ALL
    SELECT
        423,
        'BENTON',
        9
    FROM
        DUAL
    UNION ALL
    SELECT
        430,
        '99336',
        10
    FROM
        DUAL
--
--
    UNION ALL
--
--
    SELECT
        1 KEY,
        '850000900' VALUE,
        11 SEQNUM
    FROM
        DUAL
    UNION ALL
    SELECT
        2,
        'INVITAE CORPORATION',
        12
    FROM
        DUAL
    UNION ALL
    SELECT
        27,
        'Place of Service',
        13
    FROM
        DUAL
    UNION ALL
    SELECT
        39,
        'INVITAE CORPORATION',
        14
    FROM
        DUAL
    UNION ALL
    SELECT
        400,
        'XYZ 1st AVENUE',
        15
    FROM
        DUAL
    UNION ALL
    SELECT
        410,
        'SAN FRANCISCO',
        16
    FROM
        DUAL
    UNION ALL
    SELECT
        420,
        'California',
        17
    FROM
        DUAL
    UNION ALL
    SELECT
        423,
        'SAN FRANCISCO',
        18
    FROM
        DUAL
    UNION ALL
    SELECT
        430,
        '94103',
        19
    FROM
        DUAL
)
--
-- YOUR QUERY STARTS FROM HERE
--
SELECT
    MAX(CASE
        WHEN KEY = '1' THEN VALUE
    END) AS FACILITY_ID,
    MAX(CASE
        WHEN KEY = '2' THEN VALUE
    END) AS UNKNOWN_NUM,
    MAX(CASE
        WHEN KEY = '27' THEN VALUE
    END) AS TYPE_OF_LOCATION,
    MAX(CASE
        WHEN KEY = '39' THEN VALUE
    END) AS EXTERNAL_NAME,
    TRIM(',' FROM
        LISTAGG(CASE
            WHEN KEY = '400' THEN VALUE
        END, ',') WITHIN GROUP(
            ORDER BY
                SEQNUM
        )
    ) AS ADDRESS, -- ADDRESS HAS MORE THAN ONE RECORD IN THE FIRST GROUP OF VALUES
    MAX(CASE
        WHEN KEY = '410' THEN VALUE
    END) AS CITY,
    MAX(CASE
        WHEN KEY = '420' THEN VALUE
    END) AS STATE,
    MAX(CASE
        WHEN KEY = '423' THEN VALUE
    END) AS COUNTY,
    MAX(CASE
        WHEN KEY = '430' THEN VALUE
    END) AS ZIP_CODE
FROM
    (
        SELECT
            DATAA_ALL.KEY,
            DATAA_ALL.VALUE,
            DATAA_ALL.SEQNUM,
            COUNT(1) AS GRP_VAR
        FROM
            DATAA DATAA_ALL
            JOIN DATAA DATAA_FIRST ON ( DATAA_FIRST.KEY = 1
                                        AND DATAA_ALL.SEQNUM >= DATAA_FIRST.SEQNUM )
        GROUP BY
            DATAA_ALL.KEY,
            DATAA_ALL.VALUE,
            DATAA_ALL.SEQNUM
    )
GROUP BY
    GRP_VAR

Выход enter image description here

Я использовал GRP_VAR для разделения групп изатем использовал групповые функции.Кроме того, везде, где есть шансы иметь более одной записи одного и того же атрибута (как адрес в приведенном выше примере), вы можете использовать LISTAGG вместо MAX.

Cheers !!

...