是否有人知道如何区分子表中的项目?
我不确定是否可能,但也许有人可以澄清一下。
例如我有2个表:A和B(1到多个)。
如果B对应的A行具有相同的项目,我需要加入它们并从A中选择一行。
我需要在SQL服务器端执行此操作,因为我希望使用ROW_NUMBER进行分页。
更新:
CREATE TABLE [dbo].[A] ([ID] int NOT NULL, [Name] varchar(Max) NOT NULL)
CREATE TABLE [dbo].[B] ([ID] int NOT NULL, [A_ID] int NOT NULL, [Name] varchar(Max) NOT NULL)
INSERT INTO A VALUES (1, 'A1')
INSERT INTO A VALUES (2, 'A2')
INSERT INTO B VALUES (1, 1, 'B1')
INSERT INTO B VALUES (2, 1, 'B2')
INSERT INTO B VALUES (3, 2, 'B1')
INSERT INTO B VALUES (4, 2, 'B2')
这应该只返回A1,B1,B2,认为A1和A2等于它们的B1和B2。
请告诉我现在是否清楚。
答案 0 :(得分:3)
这应该可以解决问题。我投入了一些额外的CHECKSUM_AGG
魔法,所以如果你有一个非常大的桌子,它仍然会表现得很好。
WITH Grouped AS (
SELECT
A_ID,
GroupID = Checksum_Agg(Checksum(B.Name))
FROM
B
GROUP BY
B.A_ID
), DistinctA AS (
SELECT G1.A_ID
FROM
Grouped G1
WHERE
NOT EXISTS (
SELECT *
FROM Grouped G2
WHERE
G1.GroupID = G2.GroupID
AND G1.A_ID > G2.A_ID
AND NOT EXISTS (
SELECT *
FROM
(SELECT * FROM B B1 WHERE G1.A_ID = B1.A_ID) B1
FULL JOIN (SELECT * FROM B B2 WHERE G2.A_ID = B2.A_ID ) B2
ON B1.Name = B2.Name
WHERE
B1.A_ID IS NULL
OR B2.A_ID IS NULL
)
)
)
SELECT
A_ID = A.ID,
AName = A.Name,
B_ID = B.ID,
BName = B.Name
FROM
DistinctA DA
INNER JOIN A
ON DA.A_ID = A.ID
INNER JOIN B
ON A.ID = B.A_ID
;
<强> See this query live in a SQL Fiddle 强>
请注意,CHECKSUM_AGG
本身并不能保证正确性。查询的FULL JOIN
部分保证实际正确性,该部分检查Name
表中不匹配的任何B
(该组中的一个或另一个为NULL) A_ID
S)。但是CHECKSUM_AGG
充当散列函数,因此FULL JOIN
只需要比较极少数可能的重复项,而不是整个A_ID
中{1}}的所有其他B
组。表
我看到的一些事情:
ID
列是不好的。然后你必须在整个地方别名。每个表中的列A_ID
应该相同,包括A
。WhateverID
远远优于WHATEVER_ID
。即使WHATEVERID
也可以容忍。B
表可以使用另一个表加入,以查找Name
值。如果B
中具有相同名称的两行意味着相同的东西,那么其中一个拼写错误的机会成为一个非常真实的命题。相反,B
可能需要加入另一个具有所有唯一名称并提供ID的表。B
表格可能不需要ID
列(如本例所示)。在许多情况下,即使要通过密钥访问单个B行,也可以通过A_ID
和Name
(或者更好,代表名称的ID)来访问它们。 。当然,我不知道这些表中的数据究竟是什么,并且很多时候代理键是合适的。如果B实际上是一个多对多连接表,即使它有一些额外的列,大多数情况下这些表不都有一个代理键。还有一件事:如果B
表中除了Name
之外还需要多个列来了解该行是否与另一个A
的{{1}}相比是重复的行,然后就可以完成了。如果是这种情况,请告诉我。
如果您的数据在现实世界中有意义,那将会很有帮助。暴露一些关于业务对象的东西很难揭示真正私密的东西,当你的示例数据更具体时,它可以帮助那些回答你的人更好地回答。它实际上也可以帮助你更好,更快地理解你得到的答案 - 因为我上面的查询是100%抽象的,所以很难理解。
另一个注意事项:我确信希望SQL Server提供B
来补充DISUNION
,UNION
和INTERSECT
。那么这将是我使用EXCEPT
的查询部分的另一个选项。
答案 1 :(得分:1)
替代查询。比ErikE短,但在尝试添加其他列时可能会中断。
基本上,内部查询将B.Name的所有值连接成一个字符串(即“B1,B2”等)。如果B的所有部分都相同,那么您可以在外部查询中使用GROUP BY。如上所述,A.Name的选择在这个阶段是任意的,所以我做了MIN来获得第一个。
SELECT MIN(sub1.Name), sub1.conc
FROM (SELECT A.Name, (SELECT [Name]+','
FROM [b]
WHERE B.A_ID = A.ID
FOR XML PATH('')) conc
FROM [A]) sub1
GROUP BY sub1.conc