2011-06-10 105 views
2

我想在三个表上执行合并常用行的FULL OUTER JOIN三路全外连接/表合并

SELECT * FROM Users 

id Username Fullname 
== ======== ===================== 
7 iboyd  Ian Boyd 
8 nicholle Nicholle Kuzniak 
10 jamie  Jamie Bellaire 

3 row(s) affected 


SELECT * FROM GrobUsers 

id Username Fullname 
== ======== ===================== 
7 iboyd  Ian Alexander Boyd 
8 nicholle Nicholle Bachand 
9 chris  Chris Windibank 

3 row(s) affected 


SELECT * FROM FrobUsers 

id Username Fullname 
== ======== ===================== 
7 ian  Ian 
9 chris  Chris W. 
10 jamie  James Bellaire 

3 row(s) affected 

我想根据id列合并表。

这带来了的我怎么 要解决冲突时,其他 列的值不同的问题。可应用于解决用户名和全名之间的冲突算法 是:

if (id's are equal) then 
    pick one; i don't care 

我试过沿着线的东西:

SELECT 
    COALESCE(Users.id, GrobUsers.id, FrobUsers.id) AS id, 
    COALESCE(Users.Username, GrobUsers.Username, FrobUsers.Username) AS Username, 
    COALESCE(Users.FullName, GrobUsers.FullName, FrobUsers.FullName) AS Fullname 
FROM Users 
    FULL OUTER JOIN GrobUsers ON GrobUsers.id = Users.id 

    FULL OUTER JOIN FrobUsers ON FrobUsers.id = .....something...... 
+0

我还没有得到关于开发工具这台计算机没有尝试过,但是你可以使用'CROSS APPLY'然后使用'ROW_NUMBER'重新分区,并且返回ROW_NUMBER为1的行吗? – 2011-06-10 21:28:59

回答

1

在这个例子中,你给你根本不需要连接。我希望,这是一个真实的例子,而不是人为的。你想做的事情在这里很简单,你根本不需要连接,你不需要row_number。你可以这样说:

select id,Username,Fullname from Users 
UNION ALL 
select id,Username,Fullname from GrobUsers 
where id not in (select id from Users) 
UNION ALL 
select id,Username,Fullname from FrobUsers 
where id not in (select id from Users) and id not in (select id from GrobUsers) 

,它会给你:

id   Username Fullname   
----------- ---------- ----------------- 
7   iboyd  Ian Boyd   
8   nicholle Nicholle Kuzniak 
9   chris  Chris Windibank 
10   jamie  Jamie Bellaire 

(4 row(s) affected) 

下面是测试情况下,我用:

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Users]') AND type in (N'U')) 
DROP TABLE [dbo].[Users] 
GO 

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[GrobUsers]') AND type in (N'U')) 
DROP TABLE [dbo].[GrobUsers] 
GO 

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[FrobUsers]') AND type in (N'U')) 
DROP TABLE [dbo].[FrobUsers] 
GO 

CREATE TABLE [dbo].[Users](
    [Id] [int] NOT NULL, 
    [Username] [nchar](50) NULL, 
    [Fullname] [nchar](50) NULL, 
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 

CREATE TABLE [dbo].[GrobUsers](
    [Id] [int] NOT NULL, 
    [Username] [nchar](50) NULL, 
    [Fullname] [nchar](50) NULL, 
CONSTRAINT [PK_GrobUsers] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 

CREATE TABLE [dbo].[FrobUsers](
    [Id] [int] NOT NULL, 
    [Username] [nchar](50) NULL, 
    [Fullname] [nchar](50) NULL, 
CONSTRAINT [PK_FrobUsers] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 

INSERT INTO Users Values (7,'iboyd','Ian Boyd') 
INSERT INTO Users Values (8,'nicholle','Nicholle Kuzniak') 
INSERT INTO Users Values (10,'jamie','Jamie Bellaire') 


INSERT INTO [GrobUsers] Values (7,'iboyd','Ian Alexander Boyd ') 
INSERT INTO [GrobUsers] Values (8,'nicholle','Nicholle Bachand') 
INSERT INTO [GrobUsers] Values (9,'chris','Chris Windibank') 

INSERT INTO [FrobUsers] Values (7,'iboyd','Ian') 
INSERT INTO [FrobUsers] Values (9,'nicholle','Chris W.') 
INSERT INTO [FrobUsers] Values (10,'jamie','James Bellaire') 
GO 
+2

当使用'where id not in'时,您可以通过使用'union all'而不是'union'来保存服务器的某些工作。 – GSerg 2011-06-10 22:28:10

+0

@GSerg:你是对的! – 2011-06-10 22:33:19

+0

我要把它交给zespri,因为他的解决方案在2000年工作(这是我使用的),并从同一行取用户名和全名。但@GSerg,你的想法也相当不错! – 2011-06-11 02:14:00

3

一个典型的把戏 - 用聚合功能没有意义。

select id, min(username), min(fullname) from (
    SELECT * FROM Users 
    union 
    SELECT * FROM FrobUsers 
    union 
    SELECT * FROM GrobUsers 
) as foo 
group by foo.id 

嗯...但它可以从一个表中选择用户名,从另一个表中选择全名。如果你仍然不在意,使用它,否则...也许

select id, username, fullname from (
    select id, username, fullname, takeme = row_number() over (partition by id) 
    from (
    SELECT * FROM Users 
    union 
    SELECT * FROM FrobUsers 
    union 
    SELECT * FROM GrobUsers 
) as foo 
) as bar 
where bar.takeme = 1 
+0

如果您将所有表联合在一起,然后使用由ID字段划分的ROW_NUMBER()查询结果,则可以在ROW_NUMBER为1的情况下获得匹配的用户名和全名。 – 2011-06-10 21:34:11

+0

@Duncan这正是我在此期间输入的内容:) – GSerg 2011-06-10 21:37:39

+0

我认为你的意思是'id'在select子句中而不是'if'。我试着编辑它,但编辑需要超过6个字符... – 2011-06-10 21:44:14