很抱歉这是一个很长的问题而不是一个非常具有描述性的标题,但我的问题很难简单解释。

我有三个数据库表:

TABLE A:  
AID PK  
STATUS VARCHAR

TABLE B:  
BID PK  
AID FK  
CID FK

TABLE C:  
CID PK  
CREATIONTIME DATE

对于表A中的每个STATUS ='OK'行,我想在C中找到具有最新创建时间的相应行。

首先,我可以从表A中获取STATUS ='OK'的所有行 接下来,我可以从表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比CID 5更新。这意味着正确的结果将是表C中的第1,2,4和6行。

有没有办法用查询表达这个?

编辑: 对不起,我不够具体。我想得到的是表C中的CID。

编辑: 我计算了返回的行与不同的解决方案。结果非常有趣 - 而且多样化:
HAINSTECH:298 473行
JMUCCHIELLO:298 473行
RUSS CAM:290 121行
克里斯: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中查看相同的结果)并返回 C 记录的 CID ,其中包含Maximum CREATIONTIME A id 'OK'中相关记录的 STATUS

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],[最早的CreationTime]为每个AID提供最早的创建时间。

2)然后,您可以使用latestCreationTime来提取所需的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和TableC(以获取CID)。您需要执行所有明显的链接(AID,CID),并将视图中的LatestCreationTime列连接到TableC中的CreationTime列。不要忘记加入AID上的视图,否则在同一时间为不同的A记录创建了两条记录,你会遇到问题。

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中两个相同CreationTimes对同一记录的可能性。我猜这不应该发生,但是除非你写了一些绝对限制它的时间,否则需要考虑它。

要做到这一点,我需要假设你更喜欢哪一个。在这种情况下,我会说,如果有两个匹配的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

如果您真的不想在行集中创建时间,可以将其包装在子查询中并将其从投影中删除:

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世界没有什么不同的。

请注意,您提供的架构并未强制每个cid的CREATIONTIME唯一性。如果有两个cid值映射到具有相同创建时间的给定辅助值,则它们都将被输出。如果你依赖这对cid,创建时间是唯一的,你应该用约束声明性地强制执行它。

我错过了什么吗?有什么问题:

编辑:好的,我发现你确实希望通过援助进行分组。

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