2017-02-23 7 views
1

test_3, test_2test_1의 세 테이블 사이에 조인이 있습니다.GROUP BY CLOB 데이터를 가져 오는 중

test_1test_3은 주 테이블이며 공통 열은 없습니다. 테이블 test_2에 의해 결합됩니다. test_1sr_id, last_updated_date,
test_2sr_idsm_idtest_3sm_id, sql_statement을 가지고 있음. test_3에는 모든 문제를 일으키는 clob 데이터가 있습니다.

sm_id과 관련된 최신 sr_id을 찾아야합니다. 내 생각은 집계 함수 max(last_updated_date)을 사용하여 그룹화했습니다. 그리고 그것은 여러 가지 이유로 발생하지 않습니다.

  1. 이 열은 sql_statement 인 CLOB 데이터를 포함합니다.

  2. 내가 익숙하지 않은 조인을 사용했습니다.

모든 아이디어가 도움이 될 것입니다.

WITH xx as (
    (select ANSWER ,sr_id AS ID from test 
    WHERE Q_ID in (SELECT Q_ID FROM test_2 WHERE field_id='LM_LRE_Q6') 
    ) 
) 
-- end of source data 


SELECT t.ID, t1.n, t1.SM_ID,seg_dtls.SEGMENTation_NAME ,to_char(mst.LAST_UPDATED_DATE,'dd-mon-yyyy hh24:mi:ss'),seg_dtls.sql_statement 
FROM xx t 
CROSS JOIN LATERAL (
     select LEVEL AS n, regexp_substr(t.answer, '\d+', 1, level) as SM_ID 
     from dual 
     connect by regexp_substr(t.answer, '\d+', 1, level) IS NOT NULL 
) t1 
left join test_1 mst 
on mst.sr_id=t.id 
right join test_3 seg_dtls 
on seg_dtls.sm_id=t1.sm_id; 

샘플 데이터는

sr_id sm_id SEGMENTATION_NAME LAST_UPDATED_DATE 
1108197 958 test_not_in   05-feb-2017 23:56:59  
1108217 958 test_not_in   14-feb-2017 00:37:39 
1108218 958 test_not_in   14-feb-2017 01:39:50 
1108220 958 test_not_in   14-feb-2017 03:39:07 

과 같을 것이다 및 예상 출력은 거대한이기 때문에이 CLOB 데이터를 게시하고 있지 않다

1108220 958 test_not_in   14-feb-2017 03:39:07 

입니다. 모든 행에는 CLOB 데이터가 들어 있습니다.

table test_3 contains 
q_id  sr_id answer 
1009330 1108246 976~feb_24^941~Test_regionwithcountry 
1009330 1108247 941~Test_regionwithcountry_2016^787~Test_Request_28^976~feb_24 
1009330 1108239 972~test_emea 
1009330 1108240 972~test_emea^827~test_with_region_country 
1009330 1108251 981~MSE100579729 testing. 

및 샘플 데이터의 위 test_3
대답 sm_id을 포함 같습니다. 나는 여기에서 그것을 끌어 야한다. 예를 들어
:

941~Test_regionwithcountry_2016^787~Test_Request_28^976~feb_24 
the sm_id is 941,787,976 

.

위의 쿼리를 위와 같이 게시했습니다.
다시 왼쪽 및 오른쪽 조인을 사용하면 test_3의 모든 sm_id가 필요하므로 여기에 올바른 조인을 사용했습니다.

edit1 : 허용되는 대답은 최대 (last_updated_date)와 함께 SR_ID OF SEGMENTS를 제공합니다.
모든 SR_ID가 필요합니다. 그래서 MINUS 연산자를 사용하여 max (last_updated_date)가 아닌 연산자를 얻습니다.
그 결과를 허용 된 답변에 추가해야합니다.

이것은 다른 SR_ID를 얻으려고 한 것입니다.

select sr_id,segmentation_name,request_status from (with test_31 (q_id, sr_id, answer) as (
(SELECT Q_ID,SR_ID,ANSWER FROM test_3 WHERE Q_ID=(SELECT Q_ID FROM test_4 WHERE FIELD_ID='LM_LRE_Q6')) 
), 
answer_extraction as (
    select q_id, sr_id, 
    regexp_substr(regexp_substr(answer, '[^^]+', 1, level),'\d+') as sm_id 
    from test_31 
    connect by q_id = prior q_id 
    and sr_id = prior sr_id 
    and prior dbms_random.value is not null 
    and regexp_substr(answer, '[^^]+', 1, level) is not null 
) 
select sr_id, 
    sm_id, 
    segmentation_name, 
    LAST_UPDATED_DATE, 
    sql_statement,request_status 
from (
    select t1.sr_id, 
    t2.sm_id, 
    t2.segmentation_name, 
    t1.last_updated_date, 
    t2.sql_statement, 
    t1.request_status 

    from test_4 t4 
    join answer_extraction t3 on t3.q_id = t4.q_id 
    join test_2 t2 on t2.sm_id = t3.sm_id 
    join test1 t1 on t1.sr_id = t3.sr_id 
) 
) 
minus 

(select sr_id,segmentation_name , request_status from (with test_31 (q_id, sr_id, answer) as (
(SELECT Q_ID,SR_ID,ANSWER FROM test_3 WHERE Q_ID=(SELECT Q_ID FROM test_4 WHERE FIELD_ID='LM_LRE_Q6')) 
), 
answer_extraction as (
    select q_id, sr_id, 
    regexp_substr(regexp_substr(answer, '[^^]+', 1, level), '\d+') as sm_id 
    from test_31 
    connect by q_id = prior q_id 
    and sr_id = prior sr_id 
    and prior dbms_random.value is not null 
    and regexp_substr(answer, '[^^]+', 1, level) is not null 
) 
select sr_id, 
    segmentation_name, 
    sql_statement, 
    request_status 
from (
    select t1.sr_id, 
    t2.sm_id, 
    t2.segmentation_name, 
    t1.last_updated_date, 
    t2.sql_statement, 
    t1.request_status, 
    max(t1.last_updated_date) over (partition by t2.sm_id) as max_updated_date 
    from test_4 t4 
    join answer_extraction t3 on t3.q_id = t4.q_id 
    join test_2 t2 on t2.sm_id = t3.sm_id 
    join test_1 t1 on t1.sr_id = t3.sr_id 
) 
where last_updated_date = max_updated_date)); 

}

샘플 데이터 :
허용 대답 세그먼트의 최대 (LAST_UPDATED_DATE)로 출력 이하 준다.

1097661 Submitted o2k lad 30-NOV-15 01-DEC-16 62 CLOB DATA 

위의 게시 된 쿼리는 다른 업데이트 된 날짜가있는 세그먼트의 sr_id보다 아래에 출력됩니다.

1097621 o2k lad Submitted 
    1097625 o2k lad Submitted 
    1097627 o2k lad Submitted 
    1097632 o2k lad Submitted 
    1097633 o2k lad Submitted 
    1097658 o2k lad Pending 
    1097640 o2k lad Submitted 
    1097644 o2k lad Submitted 
    1097646 o2k lad Submitted 

예상 출력 : 마지막 열이 기존의 모든 SR_ID를 포함 있도록

sr_id status  segment_name updated_date sql_statement other_sr_id 
1097661 Submitted o2k lad  30-NOV-15  CLOB DATA 1097618,1097621,1097625,1097627,1097632,1097633,1097658,1097640,1097644,1097646 

는 두 개의 쿼리를 결합합니다.

+0

샘플 입력 데이터 및 예상 출력을 게시하십시오. 모든 사용자에게 도움이 될 것입니다. – Tajinder

+1

'max (last_updated_date) '를 사용하려는 원래의 계획은 질문의 코드보다 훨씬 더 유망한 것 같습니다. 어쩌면 다시 시작해야 할 것입니다. –

+0

나도 알아하지만 모든 열에는 clob이 들어있는 열도 필요하다. – user3165555

답변

0

비교적 간단한 옵션은 같은 무언가로, 각 ID의 최대 날짜를 찾아 분석 함수를 추가 할 수있는 현재의 쿼리를 수정하는 것입니다 :

..., max(mst.last_updated_date) over (partition by id) as max_updated_date 

일반적인 생각의 빠른 데모 :

with cte (id, last_updated_date, sql_statement) as (
    select 1, date '2017-01-01', to_clob('stmt 1') from dual 
    union all select 1, date '2017-01-02', to_clob('stmt 2') from dual 
    union all select 1, date '2017-01-03', to_clob('stmt 3') from dual 
    union all select 2, date '2017-01-02', to_clob('stmt 4') from dual 
) 
select id, last_updated_date, sql_statement 
from (
    select id, last_updated_date, sql_statement, 
    max(last_updated_date) over (partition by id) as max_updated_date 
    from cte 
) 
where last_updated_date = max_updated_date; 

     ID LAST_UPDAT SQL_STATEMENT                 
---------- ---------- -------------------------------------------------------------------------------- 
     1 2017-01-03 stmt 3                   
     2 2017-01-02 stmt 4                   

row_number() 또는 rank() 또는 dense_rank()를 사용하여 가장 오래된 날짜와 필터가있는 행을 식별 할 수 있지만 그 대신 일반적인 생각은 같습니다.

그러나 현재 검색어는 아직 명확하지 않습니다 (또는 12c 이전에는 유효합니다). 이러한 함수와 필터를 포함하는 방법을 추측하기보다는 기본 테이블에서 다시 시작하는 것이 더 간단 할 것입니다.하지만이 작업은 수행중인 작업에 대해 많은 가정을 수행하며 좌우 조인과 같은 일부 작업은 무시할 수 있습니다 - 실제로 필요하거나 그렇지 않을 수도 있습니다.

는 CTE를 통해 일부 데이터를 만들기 :

with test_1 (sr_id, last_updated_date) as (
    select 1108197, timestamp '2017-02-05 23:56:59' from dual 
    union all select 1108217, timestamp '2017-02-14 00:37:39' from dual 
    union all select 1108218, timestamp '2017-02-14 01:39:50' from dual 
    union all select 1108220, timestamp '2017-02-14 03:39:07' from dual 
), 
test_2 (sm_id, segmentation_name, sql_statement) as (
    select 958, 'test_not_in', to_clob('select * from dual') from dual 
), 
test_3 (q_id, sr_id, answer) as (
    select 41, 1108197, 958 from dual 
    union all select 42, 1108217, 958 from dual 
    union all select 43, 1108218, 958 from dual 
    union all select 44, 1108220, 958 from dual 
), 
test_4 (q_id, field_id) as (
    select 41, 'LM_LRE_Q6' from dual 
    union all select 42, 'LM_LRE_Q6' from dual 
    union all select 43, 'LM_LRE_Q6' from dual 
    union all select 44, 'LM_LRE_Q6' from dual 
) 

다음이 당신이 질문에 보여 같은 출력을 얻는다 : 오른쪽에 가까운 야생 가정에

select t1.sr_id, 
    t2.sm_id, 
    t2.segmentation_name, 
    to_char(t1.last_updated_date, 'dd-mon-yyyy hh24:mi:ss') as last_updated_date, 
    t2.sql_statement 
from test_4 t4 
join test_3 t3 on t3.q_id = t4.q_id 
join test_2 t2 on t2.sm_id = t3.answer 
join test_1 t1 on t1.sr_id = t3.sr_id; 

    SR_ID SM_ID SEGMENTATIO LAST_UPDATED_DATE    SQL_STATEMENT                 
---------- ----- ----------- ----------------------------- -------------------------------------------------------------------------------- 
    1108197 958 test_not_in 05-feb-2017 23:56:59   select * from dual                
    1108217 958 test_not_in 14-feb-2017 00:37:39   select * from dual                
    1108218 958 test_not_in 14-feb-2017 01:39:50   select * from dual                
    1108220 958 test_not_in 14-feb-2017 03:39:07   select * from dual                

를 찾을 수 각 최신 날짜가 sm_id 인 행은 다음과 같습니다.

명확하지 않은 다른 제한 사항이나 요구 사항 (예 : 왼쪽/오른쪽 외부 조인 포함)을 처리하기 위해이를 조정해야합니다.

나는 '응답'을 여러 값으로 나누기 위해 수행 한 하위 쿼리를 의도적으로 무시했습니다. 구분 된 ID 목록과 같은 끔찍한 점이있을 수 있습니다. 이는 데이터 모델 문제입니다. 그렇다면 개별 sm_id 값을 추출해야합니다. 같은 : 사용자가 추가 test3의 실제 내용을 바탕으로


with answer_extraction as (
    select q_id, sr_id, regexp_substr(answer, '\d+', 1, level) as sm_id 
    from test_3 
    connect by q_id = prior q_id 
    and sr_id = prior sr_id 
    and prior dbms_random.value is not null 
    and regexp_substr(answer, '\d+', 1, level) is not null 
) 
select sr_id, 
    sm_id, 
    segmentation_name, 
    to_char(last_updated_date, 'dd-mon-yyyy hh24:mi:ss') as last_updated_date, 
    sql_statement 
from (
    select t1.sr_id, 
    t2.sm_id, 
    t2.segmentation_name, 
    t1.last_updated_date, 
    t2.sql_statement, 
    max(t1.last_updated_date) over (partition by t2.sm_id) as max_updated_date 
    from test_4 t4 
    join answer_extraction t3 on t3.q_id = t4.q_id 
    join test_2 t2 on t2.sm_id = t3.sm_id 
    join test_1 t1 on t1.sr_id = t3.sr_id 
) 
where last_updated_date = max_updated_date; 
이 정규 표현식은 당신이 필요 확실히하고 있지 않습니다. 사용중인 패턴을 사용하면 14 개의 숫자 값, 즉임의의 숫자 :

with test_3 (q_id, sr_id, answer) as (
    select 1009330, 1108246, '976~feb_24^941~Test_regionwithcountry' from dual 
    union all select 1009330, 1108247, '941~Test_regionwithcountry_2016^787~Test_Request_28^976~feb_24' from dual 
    union all select 1009330, 1108239, '972~test_emea' from dual 
    union all select 1009330, 1108240, '972~test_emea^827~test_with_region_country' from dual 
    union all select 1009330, 1108251, '981~MSE100579729 testing.' from dual 
), 
answer_extraction as (
    select q_id, sr_id, regexp_substr(answer, '\d+', 1, level) as sm_id 
    from test_3 
    connect by q_id = prior q_id 
    and sr_id = prior sr_id 
    and prior dbms_random.value is not null 
    and regexp_substr(answer, '\d+', 1, level) is not null 
) 
select * from answer_extraction; 

     Q_ID  SR_ID SM_ID  
---------- ---------- ---------- 
    1009330 1108239 972  
    1009330 1108240 972  
    1009330 1108240 827  
    1009330 1108246 976  
    1009330 1108246 24   
    1009330 1108246 941  
    1009330 1108247 941  
    1009330 1108247 2016  
    1009330 1108247 787  
    1009330 1108247 28   
    1009330 1108247 976  
    1009330 1108247 24   
    1009330 1108251 981  
    1009330 1108251 100579729 

^구분 기호와 ~ 기호 사이의 비트 만 필요합니다. 구분 된 문자열을 분할하는 일반적인 방법은 다음과 같습니다.

with test_3 (q_id, sr_id, answer) as (
    select 1009330, 1108246, '976~feb_24^941~Test_regionwithcountry' from dual 
    union all select 1009330, 1108247, '941~Test_regionwithcountry_2016^787~Test_Request_28^976~feb_24' from dual 
    union all select 1009330, 1108239, '972~test_emea' from dual 
    union all select 1009330, 1108240, '972~test_emea^827~test_with_region_country' from dual 
    union all select 1009330, 1108251, '981~MSE100579729 testing.' from dual 
), 
answer_extraction as (
    select q_id, sr_id, regexp_substr(answer, '[^^]+', 1, level) as sm_id 
    from test_3 
    connect by q_id = prior q_id 
    and sr_id = prior sr_id 
    and prior dbms_random.value is not null 
    and regexp_substr(answer, '[^^]+', 1, level) is not null 
) 
select * from answer_extraction; 

     Q_ID  SR_ID SM_ID         
---------- ---------- ---------------------------------------- 
    1009330 1108239 972~test_emea       
    1009330 1108240 972~test_emea       
    1009330 1108240 827~test_with_region_country    
    1009330 1108246 976~feb_24        
    1009330 1108246 941~Test_regionwithcountry    
    1009330 1108247 941~Test_regionwithcountry_2016   
    1009330 1108247 787~Test_Request_28      
    1009330 1108247 976~feb_24        
    1009330 1108251 981~MSE100579729 testing.    

하지만 그 중 첫 번째 부분을 가져와야합니다. 원래 패턴을 빌리는 (다른 사람이 사용할 수 있습니다!) : 추가 regexp_substr()이 선택 목록에 아니라

column sm_id format a10 
with test_3 (q_id, sr_id, answer) as (
    select 1009330, 1108246, '976~feb_24^941~Test_regionwithcountry' from dual 
    union all select 1009330, 1108247, '941~Test_regionwithcountry_2016^787~Test_Request_28^976~feb_24' from dual 
    union all select 1009330, 1108239, '972~test_emea' from dual 
    union all select 1009330, 1108240, '972~test_emea^827~test_with_region_country' from dual 
    union all select 1009330, 1108251, '981~MSE100579729 testing.' from dual 
), 
answer_extraction as (
    select q_id, sr_id, 
    regexp_substr(regexp_substr(answer, '[^^]+', 1, level), '\d+') as sm_id 
    from test_3 
    connect by q_id = prior q_id 
    and sr_id = prior sr_id 
    and prior dbms_random.value is not null 
    and regexp_substr(answer, '[^^]+', 1, level) is not null 
) 
select * from answer_extraction; 

     Q_ID  SR_ID SM_ID  
---------- ---------- ---------- 
    1009330 1108239 972  
    1009330 1108240 972  
    1009330 1108240 827  
    1009330 1108246 976  
    1009330 1108246 941  
    1009330 1108247 941  
    1009330 1108247 787  
    1009330 1108247 976  
    1009330 1108251 981  

공지 사항, 하지 연결별로 절; 추출물 sm_id은 여전히 ​​문자열입니다. test_2.sm_id이 숫자이면 to_number() 호출을 해당 선택 목록의 부분 문자열 쌍에 추가하십시오.

+0

감사합니다. Alex. 귀하의 모든 가정에 자리가 있습니다. 대부분의 문제는 test_3 테이블에 있습니다. 더 많은 이해를 위해 질문을 편집 중입니다. – user3165555

+0

@ user3165555 - 당신의 대답은 내가 생각했던 것보다 더 귀하다. 당신이 실제로 관심있는 숫자를 추출하는 방법을 조금 추가했습니다, 나는 ^와 ~ 사이의 숫자입니다. 수정 된'answer_extraction' CTE를 원래 코드의 나머지 부분과 함께 사용할 수 있습니다. –

+0

알렉스, 고맙습니다.이 과정에서 많은 것을 배웠습니다. – user3165555