我有下表。
如何映射一行上的多个标签并将其转换为标签说明?有成千上万种组合。
表格:TAG_SEARCH
https://domain/API
表TAG_MAP
DATE ID TAGS
6/25/2019 101 1251:1306
6/25/2019 102 1251
6/25/2019 103 1251:1306:1274:1446:1452:1586
6/25/2019 104 1251:1306:1586
预期结果:
TAG_TYPE TAG_DESC
1251 Clothing
1306 Grocery
1274 Hardware
1446 Home_Decor
1452 Electric
1586 Plumbing
答案 0 :(得分:3)
让我们考虑如何以规范化的方式进行操作,以便数据可搜索和可累加,并且基本上是有用的。
让我们假设您被困在前两个表中
CREATE TABLE TAG_SEARCH
(TAG_DT DATE,
TAG_ID NUMBER,
TAGS VARCHAR2(4000));
CREATE TABLE TAG_MAP
(TAG_TYPE NUMBER,
TAG_DESC VARCHAR2(100));
,您正在将数据存储在输出表中:
CREATE TABLE TAGS_OUT
(TAG_DT DATE,
TAG_ID NUMBER,
TAG_DESC VARCHAR2(100));
现在,如果我们将表填充为
MERGE INTO TAG_SEARCH ts
USING (SELECT TO_DATE('6/25/2019', 'MM/DD/YYYY') AS TAG_DT, 101 AS TAG_ID, '1251:1306' AS TAGS FROM DUAL UNION ALL
SELECT TO_DATE('6/25/2019', 'MM/DD/YYYY') AS TAG_DT, 102 AS TAG_ID, '1251' AS TAGS FROM DUAL UNION ALL
SELECT TO_DATE('6/25/2019', 'MM/DD/YYYY') AS TAG_DT, 103 AS TAG_ID, '1251:1306:1274:1446:1452:1586' AS TAGS FROM DUAL UNION ALL
SELECT TO_DATE('6/25/2019', 'MM/DD/YYYY') AS TAG_DT, 104 AS TAG_ID, '1251:1306:1586' AS TAGS FROM DUAL) d
ON (d.TAG_ID = ts.TAG_ID)
WHEN NOT MATCHED THEN
INSERT (TAG_DT, TAG_ID, TAGS) VALUES (d.TAG_DT, d.TAG_ID, d.TAGS);
和
MERGE INTO TAG_MAP tm
USING (SELECT 1251 AS TAG_TYPE, 'Clothing' AS TAG_DESC FROM DUAL UNION ALL
SELECT 1306 AS TAG_TYPE, 'Grocery' AS TAG_DESC FROM DUAL UNION ALL
SELECT 1274 AS TAG_TYPE, 'Hardware' AS TAG_DESC FROM DUAL UNION ALL
SELECT 1446 AS TAG_TYPE, 'Home_Decor' AS TAG_DESC FROM DUAL UNION ALL
SELECT 1452 AS TAG_TYPE, 'Electric' AS TAG_DESC FROM DUAL UNION ALL
SELECT 1586 AS TAG_TYPE, 'Plumbing' AS TAG_DESC FROM DUAL) d
ON (d.TAG_TYPE = tm.TAG_TYPE)
WHEN NOT MATCHED THEN
INSERT (TAG_TYPE, TAG_DESC) VALUES (d.TAG_TYPE, d.TAG_DESC);
我们可以稍微滥用分层查询以使其吐出各个标签:
SELECT DISTINCT TAG_ID, LEVEL, TAG_DT, REGEXP_SUBSTR(TAGS,'[^:]+', 1, LEVEL) AS TAG_TYPE
FROM TAG_SEARCH
CONNECT BY REGEXP_SUBSTR(TAGS,'[^:]+', 1, LEVEL) IS NOT NULL
ORDER BY TAG_ID, LEVEL
一旦我们将TAG_TYPE更改为TAG_DESC,只需简单地将其适当地加入TAG_MAP表即可:
SELECT q.TAG_ID, q.LVL, q.TAG_DT, tm.TAG_DESC
FROM (SELECT DISTINCT TAG_ID, LEVEL AS LVL, TAG_DT, REGEXP_SUBSTR(TAGS,'[^:]+', 1, LEVEL) AS TAG_TYPE
FROM TAG_SEARCH
CONNECT BY REGEXP_SUBSTR(TAGS,'[^:]+', 1, LEVEL) IS NOT NULL
ORDER BY TAG_ID, LEVEL) q
INNER JOIN TAG_MAP tm
ON tm.TAG_TYPE = q.TAG_TYPE
ORDER BY q.TAG_ID, q.LVL
答案 1 :(得分:1)
同意该设计是反关系的。这只是为了表明SQL可以做到。警告:LISTAGG需要数据库版本11.2或更高版本。
更新:我忘记了标记描述的顺序应与源表中标记类型的顺序相匹配。此解决方案不遵守该顺序。 regexp_substr答案是。
create table tAG_SEARCH(DTE,ID,TAGS) as
select to_date('6/25/2019','mm/dd/yyyy'), 101, '1251:1306' from dual union all
select to_date('6/25/2019','mm/dd/yyyy'), 102, '1251' from dual union all
select to_date('6/25/2019','mm/dd/yyyy'), 103, '1251:1306:1274:1446:1452:1586' from dual union all
select to_date('6/25/2019','mm/dd/yyyy'), 104, '1251:1306:1586' from dual;
create Table TAG_MAP(TAG_TYPE,TAG_DESC) as
select 1251,'Clothing' from dual union all
select 1306,'Grocery' from dual union all
select 1274,'Hardware' from dual union all
select 1446,'Home_Decor' from dual union all
select 1452,'Electric' from dual union all
select 1586,'Plumbing' from dual;
select dte, id,
listagg(tag_desc, ':') within group(order by tag_type) tags
from tag_search ts
join tag_map tm on instr(tags, tag_type) > 0
group by dte, id
order by dte, id;
DTE ID TAGS
2019-06-25 101 Clothing:Grocery
2019-06-25 102 Clothing
2019-06-25 103 Clothing:Hardware:Grocery:Home_Decor:Electric:Plumbing
2019-06-25 104 Clothing:Grocery:Plumbing
答案 2 :(得分:1)
您可以先使用regexp_substr()
窗口分析功能进行拆分,然后使用listagg()
函数将查找表(tag_map
)中的解释连接起来
with tag_search( "Date", id, tags ) as
(
select date'2019-06-25',101,'1251:1306' from dual union all
select date'2019-06-25',102,'1251' from dual union all
select date'2019-06-25',103,'1251:1306:1274:1446:1452:1586' from dual union all
select date'2019-06-25',104,'1251:1306:1586' from dual
), tag_map( tag_type, tag_desc) as
(
select 1251, 'Clothing' from dual union all
select 1306, 'Grocery' from dual union all
select 1274, 'Hardware' from dual union all
select 1446, 'Home_Decor' from dual union all
select 1452, 'Electric' from dual union all
select 1586, 'Plumbing' from dual
), t as
(
select "Date", id, regexp_substr(tags,'[^:]+',1,level) as tags,
row_number() over (order by id, level) as lvl
from tag_search
connect by level <= regexp_count(tags,':') + 1
and prior id = id
and prior sys_guid() is not null
)
select "Date", id, listagg(tag_desc,':') within group (order by id, lvl) as tags
from t
join tag_map on tag_type = tags
group by "Date", id;
Date ID TAGS
--------- --- -------------------------------------------------------
25-JUN-19 101 Clothing:Grocery
25-JUN-19 102 Clothing
25-JUN-19 103 Clothing:Grocery:Hardware:Home_Decor:Electric:Plumbing
25-JUN-19 104 Clothing:Grocery:Plumbing