仅返回每个连接的第一个不同的行

时间:2012-09-07 10:09:46

标签: sql sql-server join distinct

情景很简单。我有4张桌子,A -table,B -table,C1 -table和C2 -table。 A是根级别表,B引用A,C1和C2引用B.但每个B.ID只能由C1或C2引用,而不能同时引用。结果被导出到.CSV文件,然后用于各种目的,这里的问题与可读性有关,并且可以更容易地管理外部软件中的信息。

我写了一个查询,它返回所有4个表中的所有数据,保持关系完整,按A,B,C1和C2排序。

SELECT A.*, B.*, C1.*, C2.*
FROM A
JOIN B 
LEFT JOIN C1
LEFT JOIN C2
ORDER BY A.ID, B.ID, etc.

得到了这个:

A.ID | B.ID | C1.ID | C2.ID
    1|     1|      1|  NULL
    1|     1|      2|  NULL
    1|     2|      1|  NULL
    1|     2|      2|  NULL
    1|     2|      3|  NULL
    2|     1|   NULL|     1
    2|     1|   NULL|     2
....

现在,问题在于:如何仅为每个连接返回第一个不同的行,以便结果集不会被冗余数据阻塞。基本上,上面的结果应该产生这个:

A.ID | B.ID | C1.ID | C2.ID
    1|     1|      1|  NULL
     |      |      2|  NULL
     |     2|      1|  NULL
     |      |      2|  NULL
     |      |      3|  NULL
    2|     1|   NULL|     1
     |      |   NULL|     2
....

我可以通过使每个连接成为子查询并按排名对结果进行分区来实现这一点,或者创建一个临时表并使用所需的逻辑对结果进行分区,但由于这将在控制台应用程序中使用,我希望尽可能保持解决方案的清洁,简单和优化。

有什么想法吗?

1 个答案:

答案 0 :(得分:4)

这是报告/格式化,而不是数据,因此它应由应用程序处理,而不是由SQL处理。

那就是说,这会产生一些接近你要求的东西

select 
    case arn when 1 then convert(varchar(10),aid) else '' end as aid,
    case brn when 1 then convert(varchar(10),bid) else '' end as bid,
    case crn when 1 then convert(varchar(10),c1id) else '' end as c1id,
    c2id        
from
(    
           select a.id aid, b.id bid, c1.id c1id, c2.id c2id,
    ROW_NUMBER() over(partition by a.id order by a.id,b.id,c1.id,c2.id) arn,
    ROW_NUMBER() over(partition by a.id,b.id order by a.id,b.id,c1.id,c2.id) brn,
    ROW_NUMBER() over(partition by a.id,b.id,c1.id order by a.id,b.id,c1.id,c2.id) crn
           FROM A 
           JOIN B  
           LEFT JOIN C1 
           LEFT JOIN C2 

) v