SQL Select : 하위 쿼리를 사용하여 3 개의 테이블간에 데이터를 결합하고 그룹화

StackOverflow https://stackoverflow.com/questions/809056

  •  03-07-2019
  •  | 
  •  

문제

긴 질문에 대해 죄송하고 설명적인 제목이 아니지만 내 문제는 간단히 설명하기가 매우 어렵습니다.

세 가지 데이터베이스 테이블이 있습니다.

TABLE A:  
AID PK  
STATUS VARCHAR

TABLE B:  
BID PK  
AID FK  
CID FK

TABLE C:  
CID PK  
CREATIONTIME DATE

각 상태에 대해 = 'OK'행에 테이블 AI의 최신 생성 시간이있는 C에서 해당 행을 찾으려고합니다.

먼저 테이블 A에서 모든 행을 가져올 수 있습니다.
다음으로 표 B에서 해당하는 모든 행을 가져올 수 있습니다.
하지만 거기에서 계속하는 방법?

예를 들어:

select AID, CID from B where AID in (select AID from A where STATUS = 'OK')

다음과 같은 것을 반환 할 수 있습니다.

AID, CID  
1    1  
2    2  
2    3  
3    4  
4    5  
4    6  

CID 2가 CID 3과 CID 6보다 나중에 생성 시간을 가지고 있다고 가정 해 봅시다. 이는 올바른 결과가 표 C에서 행 1, 2, 4 및 6임을 의미합니다.

쿼리로 이것을 표현하는 방법이 있습니까?

편집 : 내가 충분히 구체적이지 않아서 죄송합니다. 내가 얻고 싶은 것은 테이블 C의 CID입니다.

편집 : 다른 솔루션으로 반품 행을 계산했습니다. 결과는 매우 흥미롭고 다각화되었습니다.
Hainstech : 298 473 행
Jmucchiello : 298 473 행
Russ Cam : 290 121 행
Chris : 344 093 행
Tyrannosaurs : 290 119 행

아직 반품 행을 깊이 분석 할 시간이 없었지만 쿼리 중 어느 것이 "파손 된"이유에 대한 견해에 정말 감사합니다.

도움이 되었습니까?

해결책

내가 당신을 올바르게 이해했다면 이와 같은 것

SELECT
    MAX(CREATIONTIME),
    A.AID
FROM
    A
INNER JOIN
    B
    ON 
    A.AID = B.AID
INNER JOIN
    C
    ON 
    B.CID = C.CID
WHERE
    A.STATUS = 'OK'
GROUP BY
    A.AID

편집하다:

이제 SQL Server에서 다음을 확인했습니다 (Oracle에서 동일한 결과를 epxect). CIDC 최대로 기록하십시오 CREATIONTIME 어디에 STATUS 관련 레코드의 경우 A ID 'OK'.

SELECT C.CID
FROM 
C C
INNER JOIN
B B
ON 
C.CID = B.CID
INNER JOIN
(
    SELECT
        MAX(C.CREATIONTIME) CREATIONTIME,
        A.AID
    FROM
        A A
    INNER JOIN
        B B
        ON 
        A.AID = B.AID
    INNER JOIN
        C C
        ON 
        B.CID = C.CID
    WHERE
        A.STATUS = 'OK'
    GROUP BY
        A.AID
) ABC
ON B.AID = ABC.AID
AND C.CREATIONTIME = ABC.CREATIONTIME

다음과 함께 시연되었습니다 T-SQL

DECLARE @A TABLE(AID INT IDENTITY(1,1), STATUS VARCHAR(10))
DECLARE @B TABLE(BID INT IDENTITY(1,1), AID INT, CID INT)
DECLARE @C TABLE(CID INT IDENTITY(1,1), CREATIONTIME DATETIME)

INSERT INTO @A VALUES ('OK')
INSERT INTO @A VALUES ('OK')
INSERT INTO @A VALUES ('NOT OK')
INSERT INTO @A VALUES ('OK')
INSERT INTO @A VALUES ('NOT OK')

INSERT INTO @C VALUES ('10 MAR 2008')
INSERT INTO @C VALUES ('13 MAR 2008')
INSERT INTO @C VALUES ('15 MAR 2008')
INSERT INTO @C VALUES ('17 MAR 2008')
INSERT INTO @C VALUES ('21 MAR 2008')

INSERT INTO @B VALUES (1,1)
INSERT INTO @B VALUES (1,2)
INSERT INTO @B VALUES (1,3)
INSERT INTO @B VALUES (2,2)
INSERT INTO @B VALUES (2,3)
INSERT INTO @B VALUES (2,4)
INSERT INTO @B VALUES (3,3)
INSERT INTO @B VALUES (3,4)
INSERT INTO @B VALUES (3,5)
INSERT INTO @B VALUES (4,5)
INSERT INTO @B VALUES (4,1)
INSERT INTO @B VALUES (4,2)


SELECT C.CID
FROM 
@C C
INNER JOIN
@B B
ON 
C.CID = B.CID
INNER JOIN
(
SELECT
    MAX(C.CREATIONTIME) CREATIONTIME,
    A.AID
FROM
    @A A
INNER JOIN
    @B B
    ON 
    A.AID = B.AID
INNER JOIN
    @C C
    ON 
    B.CID = C.CID
WHERE
    A.STATUS = 'OK'
GROUP BY
    A.AID
) ABC
ON B.AID = ABC.AID
AND C.CREATIONTIME = ABC.CREATIONTIME

결과를 초래합니다

CID
-----------
3
4
5

편집 2 :

다른 결과를 제공하는 각 진술에 대한 귀하의 의견에 대한 응답으로 위의 테스트 데이터를 사용하여 SQL Server 2005를 통해 다른 답변 중 일부를 실행했습니다 (Oracle을 사용해 주셔서 감사합니다). 결과는 다음과 같습니다

--Expected results for CIDs would be

--CID
-----------
--3
--4
--5

--As indicated in the comments next to the insert statements

DECLARE @A TABLE(AID INT IDENTITY(1,1), STATUS VARCHAR(10))
DECLARE @B TABLE(BID INT IDENTITY(1,1), AID INT, CID INT)
DECLARE @C TABLE(CID INT IDENTITY(1,1), CREATIONTIME DATETIME)

INSERT INTO @A VALUES ('OK') -- AID 1
INSERT INTO @A VALUES ('OK') -- AID 2
INSERT INTO @A VALUES ('NOT OK')
INSERT INTO @A VALUES ('OK') -- AID 4
INSERT INTO @A VALUES ('NOT OK')

INSERT INTO @C VALUES ('10 MAR 2008')
INSERT INTO @C VALUES ('13 MAR 2008')
INSERT INTO @C VALUES ('15 MAR 2008')
INSERT INTO @C VALUES ('17 MAR 2008')
INSERT INTO @C VALUES ('21 MAR 2008')

INSERT INTO @B VALUES (1,1)
INSERT INTO @B VALUES (1,2)
INSERT INTO @B VALUES (1,3) -- Will be CID 3 For AID 1
INSERT INTO @B VALUES (2,2)
INSERT INTO @B VALUES (2,3)
INSERT INTO @B VALUES (2,4) -- Will be CID 4 For AID 2
INSERT INTO @B VALUES (3,3)
INSERT INTO @B VALUES (3,4)
INSERT INTO @B VALUES (3,5)
INSERT INTO @B VALUES (4,5) -- Will be CID 5 FOR AID 4
INSERT INTO @B VALUES (4,1)
INSERT INTO @B VALUES (4,2)

-- Russ Cam
SELECT C.CID, ABC.CREATIONTIME
FROM 
@C C
INNER JOIN
@B B
ON 
C.CID = B.CID
INNER JOIN
(
SELECT
    MAX(C.CREATIONTIME) CREATIONTIME,
    A.AID
FROM
    @A A
INNER JOIN
    @B B
    ON 
    A.AID = B.AID
INNER JOIN
    @C C
    ON 
    B.CID = C.CID
WHERE
    A.STATUS = 'OK'
GROUP BY
    A.AID
) ABC
ON B.AID = ABC.AID
AND C.CREATIONTIME = ABC.CREATIONTIME

-- Tyrannosaurs
select   A.AID,  
         max(AggC.CREATIONTIME)  
from    @A A,  
         @B B,  
         (  select  C.CID,  
             max(C.CREATIONTIME) CREATIONTIME  
            from @C C  
            group by CID
          ) AggC  
where    A.AID = B.AID  
and    B.CID = AggC.CID  
and    A.Status = 'OK'  
group by A.AID

-- jmucchiello
SELECT c.cid, max(c.creationtime)
FROM @B b, @C c
WHERE b.cid = c.cid
 AND b.aid IN (SELECT a.aid FROM @A a WHERE status = 'OK')
GROUP BY c.cid

-- hainstech
SELECT agg.aid, agg.cid
FROM (
    SELECT a.aid
        ,c.cid
        ,max(c.creationtime) as maxcCreationTime
    FROM @C c INNER JOIN @B b ON b.cid = c.cid
        INNER JOIN @A a on a.aid = b.aid
    WHERE a.status = 'OK'
    GROUP BY a.aid, c.cid
) as agg

--chris
SELECT A.AID, C.CID, C.CREATIONTIME
FROM @A A, @B B, @C C
WHERE A.STATUS = 'OK'
AND A.AID = B.AID
AND B.CID = C.CID
AND C.CREATIONTIME = 
(SELECT MAX(C2.CREATIONTIME) 
FROM @C C2, @B B2 
WHERE B2.AID = A.AID
AND C2.CID = B2.CID);

결과는 다음과 같습니다

--Russ Cam - Correct CIDs (I have added in the CREATIONTIME for reference)
CID         CREATIONTIME
----------- -----------------------
3           2008-03-15 00:00:00.000
4           2008-03-17 00:00:00.000
5           2008-03-21 00:00:00.000

--Tyrannosaurs - No CIDs in the resultset
AID         
----------- -----------------------
1           2008-03-15 00:00:00.000
2           2008-03-17 00:00:00.000
4           2008-03-21 00:00:00.000


--jmucchiello - Incorrect CIDs in the resultset
cid         
----------- -----------------------
1           2008-03-10 00:00:00.000
2           2008-03-13 00:00:00.000
3           2008-03-15 00:00:00.000
4           2008-03-17 00:00:00.000
5           2008-03-21 00:00:00.000

--hainstech - Too many CIDs in the resultset, which CID has the MAX(CREATIONTIME) for each AID?
aid         cid
----------- -----------
1           1
1           2
1           3
2           2
2           3
2           4
4           1
4           2
4           5

--chris - Correct CIDs, it is the same SQL as mine
AID         CID         CREATIONTIME
----------- ----------- -----------------------
1           3           2008-03-15 00:00:00.000
2           4           2008-03-17 00:00:00.000
4           5           2008-03-21 00:00:00.000

더 적은 수의 레코드에 대해 주어진 답변을 실행하는 것이 좋습니다. 결과 세트가 예상되는 것인지 확인할 수 있습니다.

다른 팁

SQL> create table a (aid,status)
  2  as
  3  select 1, 'OK' from dual union all
  4  select 2, 'OK' from dual union all
  5  select 3, 'OK' from dual union all
  6  select 4, 'OK' from dual union all
  7  select 5, 'NOK' from dual
  8  /

Tabel is aangemaakt.

SQL> create table c (cid,creationtime)
  2  as
  3  select 1, sysdate - 1 from dual union all
  4  select 2, sysdate - 2 from dual union all
  5  select 3, sysdate - 3 from dual union all
  6  select 4, sysdate - 4 from dual union all
  7  select 5, sysdate - 6 from dual union all
  8  select 6, sysdate - 5 from dual
  9  /

Tabel is aangemaakt.

SQL> create table b (bid,aid,cid)
  2  as
  3  select 1, 1, 1 from dual union all
  4  select 2, 2, 2 from dual union all
  5  select 3, 2, 3 from dual union all
  6  select 4, 3, 4 from dual union all
  7  select 5, 4, 5 from dual union all
  8  select 6, 4, 6 from dual union all
  9  select 7, 5, 6 from dual
 10  /

Tabel is aangemaakt.

SQL> select a.aid
  2       , max(c.cid) keep (dense_rank last order by c.creationtime) cid
  3       , max(c.creationtime) creationtime
  4    from a
  5       , b
  6       , c
  7   where b.aid = a.aid
  8     and b.cid = c.cid
  9     and a.status = 'OK'
 10   group by a.aid
 11  /

       AID        CID CREATIONTIME
---------- ---------- -------------------
         1          1 30-04-2009 09:26:00
         2          2 29-04-2009 09:26:00
         3          4 27-04-2009 09:26:00
         4          6 26-04-2009 09:26:00

4 rijen zijn geselecteerd.

3 개의 테이블의 결합을 사용하여 원하는 필드를 선택한 다음 결과를 CreationDate가 가장 최근에 한 결과로 제한하십시오.

SELECT A.AID, C.CID, C.CREATIONTIME
FROM A A, B B, C C
WHERE A.STATUS = 'OK'
AND A.AID = B.AID
AND B.CID = C.CID
AND C.CREATIONTIME = 
(SELECT MAX(C2.CREATIONTIME) 
FROM C C2, B B2 
WHERE B2.AID = A.AID
AND C2.CID = B2.CID);

편집 : 나의 이전 대답은 말도 안됩니다. 이것은 이제 완전한 재 작성입니다

이것은 실제로 내 SQL 생활을 통해 나를 괴롭힌 문제입니다. 내가 당신에게 줄 솔루션은 지옥처럼 지저분하지만 효과가 있으며 "그렇습니다. 이것은 지옥처럼 지저분하지만 그렇게하는 유일한 방법입니다"라고 말하거나 "아니요, 이걸 ... ".

불안감은 두 날짜에 참여한 것 같습니다. 여기서 일어나는 방식은 정확히 일치 할 것이기 때문에 문제가되지 않지만 (정확히 동일한 루트 데이터를 가지고 있음) 여전히 틀린 느낌이 듭니다 ...

어쨌든, 이것을 무너 뜨리려면, 당신은 두 단계로 이것을해야합니다.

1) 첫 번째는 [AID], [초기 창조 시간] 세트 세트를 반환하여 각 원조에 대한 최초의 창조 시간을 제공하는 것입니다.

2) 그런 다음 최신 제품을 사용하여 원하는 CID를 가져올 수 있습니다.

그래서 (1) 부분의 경우, 나는 개인적으로 물건을 깔끔하게 유지하기 위해 그것을하는 견해를 만들었습니다. 그것은 당신 이이 부분을 테스트하고 다른 것들과 합병하기 전에 작동하게 할 수 있습니다.

create view LatestCreationTimes
as
select b.AID,
       max(c.CreationTime) LatestCreationTime
from   TableB b,
       TableC c
where  b.CID = c.CID
group by b.AID

이 시점에서 상태를 고려하지 않았습니다.

그런 다음 Tablea (상태를 얻으려면) 및 TableB 및 Table (CID를 얻으려면)에이를 결합해야합니다. 모든 명백한 링크 (AID, CID)를 수행하고 테이블의 CreationTime 열을보기에서 최신 스테이션 타임 열에 가입해야합니다. 또한 다른 레코드에 대해 두 개의 기록이 동시에 생성 된 경우에 문제가 발생할 수있는 도구에 대한보기에 참여하는 것을 잊지 마십시오.

select A.AID,
       C.CID
from   TableA a,
       TableB b,
       TableC c,
       LatestCreationTimes lct
where  a.AID = b.AID
and    b.CID = c.CID
and    a.AID = lct.AID
and    c.CreationTime = lct.LatestCreationTime
and    a.STATUS = 'OK'

나는 그것이 효과가 있다고 확신한다 - 나는 그것을 테스트하고, 데이터를 조정하고, 그것을 다시 테스트하고, 그것이 동작한다. 적어도 그것은 내가해야한다고 믿는 것을 수행합니다.

그러나 동일한 레코드에 대해 표 C에서 두 개의 동일한 창조 시간의 가능성을 다루지 않습니다. 나는 당신이 언젠가는 그것을 절대적으로 제한하는 것을 작성하지 않는 한, 이것이 일어나지 않아야한다고 생각합니다.

이를 위해서는 원하는 것을 가정해야합니다. 이 경우 일치하는 두 개의 CID가 있다면 오히려 더 높은 CID가있을 것입니다 (최신 정보가 가장 많을 것입니다).

select A.AID,
       max(C.CID) CID
from   TableA a,
       TableB b,
       TableC c,
       LatestCreationTimes lct
where  a.AID = b.AID
and    b.CID = c.CID
and    c.CreationTime = lct.LatestCreationTime
and    a.STATUS = 'OK'
group by A.AID

그리고 그것은 당신을 위해 일해야한다고 믿습니다. 보기보다는 하나의 쿼리로 원한다면 :

select A.AID,
       max(C.CID) CID
from   TableA a,
       TableB b,
       TableC c,
       (select b.AID,
               max(c.CreationTime) LatestCreationTime
        from   TableB b,
               TableC c
        where  b.CID = c.CID
        group by b.AID) lct
where  a.AID = b.AID
and    b.CID = c.CID
and    c.CreationTime = lct.LatestCreationTime
and    a.STATUS = 'OK'
group by A.AID

(방금 쿼리에 뷰를 내장했습니다. 그렇지 않으면 교장이 정확히 동일합니다).

하위 쿼리가 필요하지 않으며 최신 CID 생성 시간을 결정하기위한 집계가 간단합니다.

SELECT a.aid
    ,c.cid
    ,max(c.creationtime) as maxcCreationTime
FROM c INNER JOIN b ON b.cid = c.cid
    INNER JOIN a on a.aid = b.aid
WHERE a.status = 'OK'
GROUP BY a.aid, c.cid

당신이 정말로 당신의 행 세트에서 CreationTime을 원하지 않는다면, 당신은 그것을 서브 쿼리로 랩핑하고 프로젝션에서 떨어 뜨릴 수 있습니다.

SELECT agg.aid, agg.cid
FROM (
    SELECT a.aid
        ,c.cid
        ,max(c.creationtime) as maxcCreationTime
    FROM c INNER JOIN b ON b.cid = c.cid
        INNER JOIN a on a.aid = b.aid
    WHERE a.status = 'OK'
    GROUP BY a.aid, c.cid
) as agg

웹 페이지에서 코딩하면 구문 실수를 실례합니다. 또한, 나는 MSSQL 사람이므로 Oracle World에서 이것에 대해 다른 것이 없기를 바랍니다 ..

제공 한 스키마는 CID 당 창조 시간의 독창성을 시행하지 않습니다. 동일한 창조 시간으로 주어진 원조 값에 매핑되는 두 가지 CID 값이 있다면 둘 다 출력됩니다. CID 쌍에 의존하면 CreationTime이 독특 해지면 제약으로 선언적으로 시행해야합니다.

내가 뭔가를 놓치고 있습니까? 무엇이 문제가 있습니까 :

편집 : 알겠습니다. 실제로 원조로 그룹화하고 싶어합니다.

SELECT c.cid FROM b, c,
    (SELECT b.aid as aid, max(c.creationtime) as creationtime
     FROM b, c
     WHERE b.cid = c.cid
       AND b.aid IN (SELECT a.aid FROM a WHERE status = 'OK')
     GROUP BY b.aid) as z
WHERE b.cid = c.cid
  AND z.aid = b.aid
  AND z.creationtime = c.creationtime
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top