2011-06-10 81 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