2017-12-11 17 views
1

백업 어플라이언스 (Avamar)의 ProgreSQL DB 테이블에서 백업 작업에 대한 세부 정보를 수집하려고합니다. 이 테이블에는 client_name, dataset, plugin_name, type, completed_ts, status_code, bytes_modified 등 여러 열이 있습니다. 간단한 예 :GROUP BY 결과에 기초한 다중 자체 조인

| session_id | client_name | dataset |   plugin_name |    type |   completed_ts | status_code | bytes_modified | 
|------------|-------------|---------|---------------------|------------------|----------------------|-------------|----------------| 
|   1 | server01 | Windows | Windows File System | Scheduled Backup | 2017-12-05T01:00:00Z |  30900 |  11111111 | 
|   2 | server01 | Windows | Windows File System | Scheduled Backup | 2017-12-04T01:00:00Z |  30000 |  22222222 | 
|   3 | server01 | Windows | Windows File System | Scheduled Backup | 2017-12-03T01:00:00Z |  30000 |  22222222 | 
|   4 | server01 | Windows | Windows File System | Scheduled Backup | 2017-12-02T01:00:00Z |  30000 |  22222222 | 
|   5 | server01 | Windows |   Windows VSS | Scheduled Backup | 2017-12-01T01:00:00Z |  30000 |  33333333 | 
|   6 | server02 | Windows | Windows File System | Scheduled Backup | 2017-12-05T02:00:00Z |  30000 |  44444444 | 
|   7 | server02 | Windows | Windows File System | Scheduled Backup | 2017-12-04T02:00:00Z |  30900 |  55555555 | 
|   8 | server03 | Windows | Windows File System | On-Demand Backup | 2017-12-05T03:00:00Z |  30000 |  66666666 | 
|   9 | server04 | Windows | Windows File System |   Validate | 2017-12-05T03:00:00Z |  30000 |  66666666 | 

각 클라이언트 _ (서버)는 복수의 데이터 세트를 가질 수 있으며, 각 세트는 복수 plugin_names을 가질 수있다. 그래서 나는 시간이 지남에 따라 "job"활동의 목록을 얻기 위해이 세 컬럼의 GROUP BY를 수행하는 SQL 문을 작성했습니다.

select 
    client_name, 
    dataset, 
    plugin_name 
from v_activities_2 
where 
    type like '%Backup%' 
group by 
    client_name, dataset, plugin_name 

이러한 작업의 각 (http://sqlfiddle.com/#!15/f15556/1)

는 성공할 수 또는 STATUS_CODE 열을 기반으로 실패. 사용 나는 그것의 completed_ts (완료 시간)와 함께 마지막으로 좋은 백업의 결과를 얻을 수 및 bytes_modified하고있어 하위 쿼리와 자체 조인 더 : ( http://sqlfiddle.com/#!15/f15556/16)

select 
    a2.client_name, 
    a2.dataset, 
    a2.plugin_name, 
    a2.LastGood, 
    a3.status_code, 
    a3.bytes_modified as LastGood_bytes 
from v_activities_2 a3 

join (
    select 
    client_name, 
    dataset, 
    plugin_name, 
    max(completed_ts) as LastGood 
    from v_activities_2 a2 
    where 
    type like '%Backup%' 
    and status_code in (30000,30005) -- Successful (Good) Status codes 
    group by 
    client_name, dataset, plugin_name 
) as a2 
on a3.client_name = a2.client_name and 
    a3.dataset  = a2.dataset and 
    a3.plugin_name = a2.plugin_name and 
    a3.completed_ts = a2.LastGood 

내가 별도로 같은 일을 할 수 WHERE의 status_code 행을 제거하여 마지막 시도 세부 정보를 얻으십시오 : http://sqlfiddle.com/#!15/f15556/3. 대부분의 시간 LastGood와 LastAttempted는 동일한 행이지만 마지막 백업이 성공했는지에 따라 그렇지 않은 경우가 있습니다.

나는이 두 문장을 가능한 병합하여 병합하고 있습니다.

난 그냥 다른 권리를 추가 시도 된
| client_name | dataset |   plugin_name |    lastgood | lastgood_bytes |   lastattempt | lastattempt_bytes | 
|-------------|---------|---------------------|----------------------|-----------------|----------------------|-------------------| 
| server01 | Windows | Windows File System | 2017-12-04T01:00:00Z |  22222222 | 2017-12-05T01:00:00Z |   11111111 | 
| server01 | Windows |   Windows VSS | 2017-12-01T01:00:00Z |  33333333 | 2017-12-01T01:00:00Z |   33333333 | 
| server02 | Windows | Windows File System | 2017-12-05T02:00:00Z |  44444444 | 2017-12-05T02:00:00Z |   44444444 | 
| server03 | Windows | Windows File System | 2017-12-05T03:00:00Z |  66666666 | 2017-12-05T03:00:00Z |   66666666 | 

최종 (http://sqlfiddle.com/#!15/f15556/4) 및 NULL 행을 얻기에 가입 : 그래서이 결과를 얻을 것이다. 몇 가지 독서를 한 후에 처음 두 JOIN이 2 차 조인이 발생하기 전에 임시 테이블을 먼저 작성했지만 그 시점에서 필요한 데이터가 손실되어 NULL 행이 표시되는 것을 볼 수 있습니다.

groovy 스크립팅을 통한 PostgreSQL 8 사용. 또한 DB에 대한 읽기 전용 액세스 권한도 있습니다.

+0

가능한 중복 GROUP \ _BYs의 2 개의 LEFT JOIN] (https://stackoverflow.com/questions/45250646/strange-duplicate-behavior-from-group-concat-of-two-left-joins-of-group-bys) – philipxy

+0

감사. v_activities_2는 Avamar 장비가 읽기 전용 액세스를 제공하는보기입니다. 나는 실제 데이터베이스 테이블이나 제약 조건에 대해 알지 못한다. 각보기에 대한 설명과 열의 의미 만 있습니다. 나는 client_name, dataset, plugin_name이 함께 Common Key (CK)를 형성하고 그 CK에 기반하여 테이블을 조인/병합하려고 시도했다는 것에 동의한다. – Halfdone

+0

저는 두 가지 작동 솔루션을 생각해 냈습니다 : http://sqlfiddle.com/#!15/f15556/114 및 http://sqlfiddle.com/#!15/f15556/149 따라와 더 빨리). 나는 나의 상황에서 LastGood가 없을 수도있는 동안 LastAttempt도있을 것이라는 것을 깨닫는 데 도움이되는 하나의 항목을 추측합니다. – Halfdone

답변

1

분명히 중간에 두 개의 중간 출력 테이블이 있고 공통 키로 식별되는 몇 가지 항목을 가져 오려고합니다. 그래서 inner join 열쇠에.

select 
    g.client_name, 
    g.dataset, 
    g.plugin_name, 
    LastGood, 
    g.status_code, 
    LastGood_bytes 
    LastAttempt, 
    l.status_code, 
    LastAttempt_bytes 
from 
(-- cut & pasted Last Good http://sqlfiddle.com/#!15/f15556/16 
    select 
     a2.client_name, 
     a2.dataset, 
     a2.plugin_name, 
     a2.LastGood, 
     a3.status_code, 
     a3.bytes_modified as LastGood_bytes 
    from v_activities_2 a3 
    join (
     select 
     client_name, 
     dataset, 
     plugin_name, 
     max(completed_ts) as LastGood 
     from v_activities_2 a2 
     where 
     type like '%Backup%' 
     and status_code in (30000,30005) -- Successful (Good) Status codes 
     group by 
     client_name, dataset, plugin_name 
    ) as a2 
    on a3.client_name = a2.client_name and 
     a3.dataset  = a2.dataset and 
     a3.plugin_name = a2.plugin_name and 
     a3.completed_ts = a2.LastGood 
) as g 
join 
(-- cut & pasted Last Attempt http://sqlfiddle.com/#!15/f15556/3 
    select 
     a1.client_name, 
     a1.dataset, 
     a1.plugin_name, 
     a1.LastAttempt, 
     a3.status_code, 
     a3.bytes_modified as LastAttempt_bytes 
    from v_activities_2 a3 
    join (
     select 
     client_name, 
     dataset, 
     plugin_name, 
     max(completed_ts) as LastAttempt 
     from v_activities_2 a2 
     where 
     type like '%Backup%' 
     group by 
     client_name, dataset, plugin_name 
    ) as a1 
    on a3.client_name = a1.client_name and 
     a3.dataset  = a1.dataset and 
     a3.plugin_name = a1.plugin_name and 
     a3.completed_ts = a1.LastAttempt 
) as l 
on l.client_name = g.client_name and 
    l.dataset  = g.dataset and 
    l.plugin_name = g.plugin_name 
order by client_name, dataset, plugin_name 

여기에는 Strange duplicate behavior from GROUP_CONCAT of two LEFT JOINs of GROUP_BYs의 적용 가능한 방법 중 하나가 사용됩니다. 그러나 코드 덩어리의 대응은 그렇게 명확하지 않을 수도 있습니다. 그 중간은 left 대 귀하의 inner & group_concatmax입니다. (그러나 때문에 group_concat &의 쿼리 내역의 많은 방법이있다.)

원래 올바른 대칭 INNER 접근 가입 : LEFT는 Q1에게 & q2--1 가입 : 많은 - 다음 그룹을 & GROUP_CONCAT에 의해 (무엇 인 귀하의 첫 번째 쿼리 않았다); 그런 다음 별도로 비슷하게 LEFT JOIN q1 & q3--1 : many - then GROUP BY & GROUP_CONCAT; INNER는 user_id - 1 : 1의 두 결과를 조인합니다.

원래 올바른 누적 LEFT

은 접근 가입 : Q1에게 & q2--1 가입 : 많은 - 다음 그룹을 & GROUP_CONCAT에 의해; 그런 다음 & q3--1 : many - then GROUP BY & GROUP_CONCAT에 참여하십시오.

실제로이 기능이 일반 용도로 사용되는지 여부는 실제 사양 및 제약 사항에 따라 다릅니다. 두 개의 join이 링크되어 있어도 원하는대로 "병합"을 정확히 설명해야합니다. join에 그룹화 된 열에 대해 다른 값 집합이있는 경우 원하는 것을 말하지 않습니다. 입력에 어떤 행이 있는지에 따라 결과에서 어떤 행이 표시되는지 영어로 나타내십시오.

PS 1 문서화되지 않은/신고되지 않은/적용되지 않은 제약이 있습니다. 가능한 경우 신고하십시오. 그렇지 않으면 트리거에 의해 시행하십시오. 코드에없는 경우 질문 텍스트로 문서화하십시오. 제약은 복수 서브 로우 값 인스턴스의 기본입니다. join & ~ group by.

PS 2 select의 구문/의미를 확인하십시오. 자세히 알아보기 left/rightouter join on 반환 - 무엇 inner join on 더하기 일치하지 않는 왼쪽/오른쪽 테이블 행은 null에 의해 확장. 여기에 PS 3 Is there any rule of thumb to construct SQL query from a human-readable description?

0

또한 내 데이터 세트에 따라야하지만, 열심히하고 가능성이 더 특정 작동하는 또 다른 방법입니다 : http://sqlfiddle.com/#!15/f15556/114

select 
    Actvty.client_name, 
    Actvty.dataset, 
    Actvty.plugin_name, 
    ActvtyGood.LastGood, 
    ActvtyGood.status_code as LastGood_status, 
    ActvtyGood.bytes_modified as LastGood_bytes, 
    ActvtyOnly.LastAttempt, 
    Actvty.status_code as LastAttempt_status, 
    Actvty.bytes_modified as LastAttempt_bytes 
from v_activities_2 Actvty 

-- 1. Get last attempt of each job (which may or may not match last good) 
join (
    select 
    client_name, 
    dataset, 
    plugin_name, 
    max(completed_ts) as LastAttempt 
    from v_activities_2 
    where 
    type like '%Backup%' 
    group by 
    client_name, dataset, plugin_name 
) as ActvtyOnly 
on Actvty.client_name = ActvtyOnly.client_name and 
    Actvty.dataset  = ActvtyOnly.dataset and 
    Actvty.plugin_name = ActvtyOnly.plugin_name and 
    Actvty.completed_ts = ActvtyOnly.LastAttempt 

-- 4. join the list of good runs with the table of last attempts, there would never be a job that has a last good without also a last attempt. 
join (

    -- 3. join last good runs with the full table to get the additional details of each 
    select 
    ActvtyGoodSub.client_name, 
    ActvtyGoodSub.dataset, 
    ActvtyGoodSub.plugin_name, 
    ActvtyGoodSub.LastGood, 
    ActvtyAll.status_code, 
    ActvtyAll.bytes_modified 
    from v_activities_2 ActvtyAll 

    -- 2. Get last Good run of each job 
    join (
    select 
     client_name, 
     dataset, 
     plugin_name, 
     max(completed_ts) as LastGood 
    from v_activities_2 
    where 
     type like '%Backup%' 
     and status_code in (30000,30005) -- Successful (Good) Status codes 
    group by 
     client_name, dataset, plugin_name 
) as ActvtyGoodSub 
    on ActvtyAll.client_name = ActvtyGoodSub.client_name and 
    ActvtyAll.dataset  = ActvtyGoodSub.dataset and 
    ActvtyAll.plugin_name = ActvtyGoodSub.plugin_name and 
    ActvtyAll.completed_ts = ActvtyGoodSub.LastGood 

) as ActvtyGood 
on Actvty.client_name = ActvtyGood.client_name and 
    Actvty.dataset  = ActvtyGood.dataset and 
    Actvty.plugin_name = ActvtyGood.plugin_name 
의 그룹의 \의 _CONCAT에서 [이상한 중복 행동의