Как создать столбец, содержащий JSON, имена которого определены из значения столбца в другой таблице? - PullRequest
0 голосов
/ 27 июня 2018

У меня есть исходная таблица с данными в формате VARCHAR, как в примере ниже. Я хочу вставить данные в другую таблицу в формате JSON (сам столбец результата может иметь тип JSON или VARCHAR).

  • Для каждого идентификатора существует как минимум 1 пара JSONName / JSONValue.
  • Но у каждого идентификатора нет одинаковых видов и количества пар JSONName / JSONValue.
  • Каждый идентификатор может содержать до 50 пар JSONName / JSONValue.
  • Порядок пар в значении столбца ResultJSON не имеет значения.

SourceTable:
____________________________
| Id | JSONName | JSONValue |
|____|__________|___________|
| 1  | Name     | John      |
| 2  | Name     | Henry     |
| 2  | Age      | 32        |
| 3  | Age      | 56        |
| 3  | Location | US        |
| 4  | Age      | 24        |
| 4  | Name     | Andrew    |
| 4  | Location |           |

Что я хочу:

Expected ResultTable:
____________________________________________________
| Id |               ResultJSON                     |
|____|______________________________________________|
| 1  | {"Name":"John"}                              |
| 2  | {"Name":"Henry","Age":"32"}                  |
| 3  | {"Age":"56", "Location":"US"}                |
| 4  | {"Age":"24","Name":"Andrew","Location":null} |

Что я получу с моим текущим запросом:

Wrong resultTable:
_______________________________________________________________________________________________________________________________
| Id |               ResultJSON                                                                                                |
|____|_________________________________________________________________________________________________________________________|
| 1  | [{"JSONName":"Name","JSONValue":"John"}]                                                                                |
| 2  | [{"JSONName":"Name","JSONValue":"Henry"},{"JSONName":"Age","JSONValue":"32"}]                                           |
| 3  | [{"JSONName":"Age","JSONValue":"56"},{"JSONName":"Location","JSONValue":"US"}]                                          |
| 4  | [{"JSONName":"Age","JSONValue":"24"},{"JSONName":"Name","JSONValue":"Andrew"},{"JSONName":"Location","JSONValue":null}] |

Текущий запрос:

INSERT INTO ResultTable
(
     Id
    ,ResultJSON
)
SELECT
     SourceTable.Id
    ,JSON_AGG(SourceTable.JSONName,SourceTable.JSONValue)
FROM SourceTable
INNER JOIN OtherTable ON SourceTable.Id=OtherTable.Id

Возможно ли это сделать с помощью функций Teradata JSON? Если нет, то какой запрос будет наиболее оптимизирован для этого?

Ответы [ 2 ]

0 голосов
/ 24 августа 2018

Вы можете удалить ненужные детали, используя RegEx:

SELECT
   SourceTable.Id
  ,RegExp_Replace(Cast(Json_Agg(SourceTable.JSONName AS "#A",SourceTable.JSONValue AS "#B") AS VARCHAR(32000)), '"#A":|,"#B"|^\[|\]$|}(?=,{")|(?<="},){')
FROM SourceTable
GROUP BY 1

RegEx удаляет все следующие:

  • "#A":
  • ,"#B"
  • ведущий [
  • трейлинг ]
  • }, если за ним следует ,{"
  • { если он следует "},

Edit:

На основании комментариев RegEx оставляет лишние открывающие скобки. Кажется, это работает лучше:

'"#A":|,"#B"|^[|]$|}(?=,)|(?<=,){'
0 голосов
/ 24 августа 2018

Вот запрос, который я получил в итоге:

INSERT INTO DB.RESULT_TABLE
(
     ResultId
    ,ResultJSON
)
WITH RECURSIVE MergedTable (Id, mergedList, rnk)
AS
(
    SELECT
         Id
        ,TRIM('"' || JSONName ||'":'|| COALESCE('"' || JSONValue || '"','null')) AS mergedList
        ,rnk
    FROM DB.SOURCE_TABLE
    WHERE rnk = 1

    UNION ALL

    SELECT
         SourceTable.Id
        ,MergedTable.mergedList || ',' || TRIM('"' || SourceTable.JSONName ||'":' || COALESCE('"' || SourceTable.JSONValue || '"','null')) AS mergedList
        ,SourceTable.rnk
    FROM DB.SOURCE_TABLE SourceTable
    INNER JOIN MergedTable MergedTable
        ON MergedTable.rnk + 1 = SourceTable.rnk
        AND  SourceTable.Id = MergedTable.Id
)
SELECT
     MergedTable.Id                       AS ResultId
    ,'{' || MergedTable.mergedList || '}' AS ResultJSON
FROM MergedTable
QUALIFY RANK() OVER (PARTITION BY ResultId ORDER BY rnk DESC) = 1
;
...