示例数据:
Table1 Table2
x | y x | y
----- -----
1 | A 1 | A
1 | B 1 | D
1 | C 2 | M
1 | null 2 | N
2 | M 2 | M
2 | N 1 | A
我想计算Table2中x的数量并将其与Table1连接。但在表2中,我可以得到与表1中的y不匹配的y。在这种情况下,我想在Table1的y列中使用null与row连接。 在示例中,Table2.1-D应与Tabl1.1-null
连接对于给定的例子,我期待结果:
x | y | count
-----------------
1 | A | 2
1 | B | 0
1 | C | 0
1 | null | 1 (because D doesn't match to anything else in Table1)
2 | M | 2
2 | N | 1
答案 0 :(得分:2)
我无法想到一种非常优雅的方法来实现这一目标。以下是一些蛮力,但它完成了工作:
select t1.x, t1.y,
(case when t1.y is null then unmatched.cnt else matched.cnt end) as cnt
from table1 t1 outer apply
(select count(*) as cnt
from table2 t2
where t2.y = t1.y
) matched cross join
(select count(*) as cnt
from table2 t2
where not exists (select 1 from table1 t1 where t1.y = t2.y)
) unmatched;
答案 1 :(得分:0)
有多种方法可以解决这个问题,最好的方法取决于数据,行数和最终的性能。
其中一种方法是对null
以外的所有内容进行操作,然后Table1
使用UNION
行进行操作。
对于您的示例,我假设null
和x
中y
和Table1
值的组合始终是唯一的。如果不是,你需要额外的分组。
Table2
答案 2 :(得分:0)
这是我提出的最好的:
SELECT t1.x
, t1.y
, [count] = ISNULL(t2.cnt,0)
FROM #Table1 t1
LEFT JOIN (SELECT x
, y
, cnt = COUNT(*)
FROM #Table2
GROUP BY x, y
) t2
ON (t1.x = t2.x
AND t1.y = t2.y
AND t1.y IS NOT NULL
)
OR (t1.x = t2.x
AND ISNULL(t1.y,t2.y) = t2.y
AND NOT EXISTS (SELECT 1 FROM #Table1 WHERE y = t2.y)
)
答案 3 :(得分:0)
这是一个解决方案。看看这是否有帮助!
WITH v_t2 AS
(SELECT y, COUNT(*) AS cnt
FROM table2 t2
GROUP BY t2.y
),
v_t2_null AS
(SELECT COUNT(*) AS cnt
FROM table2 t2
WHERE NOT EXISTS (SELECT 1 FROM table1 t1 WHERE t1.y= t2.y)
)
SELECT t1.x. t1.y, COALESCE(t2.cnt, v_t2_null.cnt)
FROM table1 t1 LEFT JOIN v_t2 t2
ON (t1.y = t2.y)
JOIN v_t2_null;
输出
x y cnt
1 A 2
1 B 0
1 V 0
1 NULL 1
2 M 2
2 N 1
答案 4 :(得分:0)
如果我的理解是正确的,那么它不仅仅是一个左连接问题,它是这样的:
-- Creating example
CREATE TABLE #T1 (x int, y char(1) null)
CREATE TABLE #T2 (x int, y char(1) null)
-- Loading tables
INSERT INTO #T1
SELECT 1,'A'
UNION ALL SELECT 1,'B'
UNION ALL SELECT 1,'C'
UNION ALL SELECT 1,null
UNION ALL SELECT 2,'M'
UNION ALL SELECT 2,'N'
INSERT INTO #T2
SELECT 1 ,'A'
UNION ALL SELECT 1 ,'D'
UNION ALL SELECT 2 ,'M'
UNION ALL SELECT 2 ,'N'
UNION ALL SELECT 2 ,'M'
UNION ALL SELECT 1 ,'A'
SELECT t1.x, t1.y, count(t2.y) FROM #T1 t1
LEFT JOIN #T2 t2 on t1.y = t2.y
LEFT JOIN #T2 t22 on t1.Y IS NULL AND t22.y IS NULL
WHERE t1.y is not null
GROUP BY t1.x, t1.y
UNION ALL
SELECT t.x, t.y, (SELECT count(1) 'count' FROM #T2 t2
LEFT JOIN #T1 t1 on t1.y = t2.y
WHERE t1.y IS NULL
) FROM #T1 t WHERE t.y IS NULL
我不得不将问题分成两部分。
答案 5 :(得分:0)
另一种方法我们可以通过自联接和分组连接两个表来实现这一点,如下所示
select t1.*,t2.c from Table1 t1 join
(
select
a.y,
sum(case when b.y is null then 0 else 1 end) as c
from Table1 a
full outer join
Table2 b
on
a.y=b.y
group by a.y
)t2
on ISNULL(t1.y,-1)=ISNULL(t2.y,-1)
答案 6 :(得分:0)
感谢您的所有答案。 他们非常有帮助。 这是我的解决方案,以正确的方式计算Table2中的所有行,并将其与x匹配到table1中的行,y == null。 我知道我可以在左连接中更好地使用子查询。
当然,真正的问题很复杂,问题是它的简化版本。
我发现如何改进查询,请告诉我:)
;with T2Count as
(
select x, y, count(*) cnt from @t2 group by x, y
)
/*
select t1.x, t1.y, isnull(t2.cnt, 0)
from @T1 t1
left join T2Count t2 on t1.x = t2.x and t1.y = t2.y
where t1.y is not null
*/
select t1.x, t1.y, isnull(AllCounts.cnt, 0) cnt from @t1 t1
left join (
select * from T2Count -- I know that here I'will take too much data 1-D, 2-Q, but those data will not natch in last join (AllCounts...)
union all
select t2.x, null, sum(cnt) cnt
from T2Count t2
left join @t1 t1 on t1.x = t2.x and t1.y = t2.y
where t1.x is null
group by t2.x
) as AllCounts on t1.x = AllCounts.x and (t1.y = AllCounts.y or (t1.y is null and AllCounts.y is null))