2017-06-28 77 views
1

我无法理解如何在不创建重复记录的情况下将三个表连接在一起。如何正确加入和分组

我有一个使用表的个人资料我的第一个查询,多部未华仪器:

SELECT 
    [p].[shopper_id] 
, [pi].[instrument_id] 
FROM 
    [dbo].[profile] [p] 
INNER JOIN [dbo].[profile_instruments] [pi] 
ON [pi].[PID] = [p].[PID] 
WHERE 
    [p].[date_created] > DATEADD(yy, -2, GETDATE()) 
    AND [p].[shopper_id] = '53D5444535434747A935E207C9EDD96A' 
ORDER BY 
    [p].[shopper_id]; 

该查询给我的结果:

shopper_id instrument_id 
53D5444535434747A935E207C9EDD96A 35 
53D5444535434747A935E207C9EDD96A 17 

我的第二个查询使用表的个人资料和表格样式:

SELECT 
    [p].[shopper_id] 
, [ps].[style_id] 
FROM 
    [dbo].[profile] [p] 
INNER JOIN [dbo].[profile_styles] [ps] 
ON [ps].[PID] = [p].[PID] 
WHERE 
    [p].[date_created] > DATEADD(yy, -2, GETDATE()) 
    AND [p].[shopper_id] = '53D5444535434747A935E207C9EDD96A' 
ORDER BY 
    [p].[shopper_id]; 

结果是:

shopper_id style_id 
53D5444535434747A935E207C9EDD96A 845 
53D5444535434747A935E207C9EDD96A 291 

当我结合了3代表的个人资料,仪器仪表和风格:

SELECT 
    [p].[shopper_id] 
    , [pi].[instrument_id] 
    , [ps].[style_id] 
FROM 
    [dbo].[profile] [p] 
INNER JOIN [dbo].[profile_instruments] [pi] 
ON [pi].[PID] = [p].[PID] 
INNER JOIN [dbo].[profile_styles] [ps] 
ON [ps].[PID] = [p].[PID] 
WHERE 
    [p].[date_created] > DATEADD(yy, -2, GETDATE()) 
    AND [p].[shopper_id] = '53D5444535434747A935E207C9EDD96A' 
ORDER BY 
    [p].[shopper_id]; 

我得到的结果:

shopper_id instrument_id style_id 
53D5444535434747A935E207C9EDD96A 35 845 
53D5444535434747A935E207C9EDD96A 35 291 
53D5444535434747A935E207C9EDD96A 17 845 
53D5444535434747A935E207C9EDD96A 17 291 

我没有使用一组通过但因为我不能确定如何将其应用于我拥有的专栏。我也不确定重复项是因为我使用的连接类型,还是因为我没有使用群组。

无论如何,我想寻求一些帮助,以便能够找出我需要什么修改我的查询,以使有一个输出,看起来像:

shopper_id instrument_id style_id 
53D5444535434747A935E207C9EDD96A 35 845 
53D5444535434747A935E207C9EDD96A 17 291 

谢谢提前寻求你的帮助。

+0

我们如何知道instrument_ID 35与style_ID 845而不是291?简单地说,你错过了一个定义这种关系的关联。没有它你会看到你看到的4个结果。所以在最后的加入你需要一个和PS。 = PI。表示哪种乐器与哪种风格的关系。如果无关紧要,您可以为每条记录分配一个行号并加入行号,但是这假设两个表的每个购物者的记录数相等。 – xQbert

+0

他们彼此独立。配置文件和乐器以及配置文件和样式之间有关系,但不在乐器和样式之间。 –

+0

那么我们怎么知道35会转到845而不是291?在这个例子中我再次看不到2条记录的预期结果。如果它真的没有关系,那么行数概念可能会起作用;但它假定每个表中的记录数相等,或者当每个购物者的记录数不相等时,您需要使用外部联接。 – xQbert

回答

2

也许......

我们指定一个行号,以每一款式和仪器每个PID。那么我们不仅可以通过PID加入,我们可以通过Row_number加入,这保证了当pID有2个乐器和两个风格时,我们仍然只能得到2个记录;而不是4.

使用完整的外部连接,因为我不知道是否想要查看存在2个乐器但仅存在1个乐器或2个乐器的情况。

SELECT [p].[shopper_id] 
    , [pi].[instrument_id] 
    , [ps].[style_id] 
FROM [dbo].[profile] [p] 
INNER JOIN (SELECT A.*, row_number() over (partition by PID order by instrument_ID) RN 
      FROM [dbo].[profile_instruments] A) [pi] 
    ON [pi].[PID] = [p].[PID] 
FULL OUTER JOIN (SELECT A.*, Row_number() over (partition by PID order by style_ID) RN 
       FROM [dbo].[profile_styles] A) [ps] 
    ON [ps].[PID] = [p].[PID] 
AND [PI].[RN] = [PS].[RN] 
WHERE [p].[date_created] > DATEADD(yy, -2, GETDATE()) 
    AND [p].[shopper_id] = '53D5444535434747A935E207C9EDD96A' 
ORDER BY [p].[shopper_id]; 

我们也许可以用在PI.RN一个COALESCE或PS.RN或两个,如果你愿意接受的是,当样式和手段有不同的计数,在任一台匹配到一个值接受

例子:

PID STYLE_ID  PID Instrument_ID 
1 A    1 Z 
1 B 

The above should return 
1 A Z 
1 B 

But maybe you want 
1 A Z 
1 B Z 

如果我们改变AND [PI].[RN] = [PS].[RN]AND coalesce([PI].[RN],1) = coalesce([PS].[RN],1)但是测试需要发生,这可能工作。就好像一方没有pid的所有记录,你仍然可以在一张桌子上得到空。

+0

嗨xQbert,当我尝试使用你的例子时,它引发语法错误:Msg 102,Level 15,State 1,Line 7 'row_number'附近的语法错误。 Msg 156,Level 15,State 1,Line 10 关键字'over'附近的语法不正确。 –

+0

我在第二个子查询的row_number之后缺少()。和第一个查询中的逗号后面的逗号(thx SqlZim) – xQbert

+0

我应该注意,如果插入或更改了样式或分期付款ID,则关联可能会更改 – xQbert

0

尝试进行自然连接,将类似于此:

SELECT 
    [p].[shopper_id], 
    [pi].[instrument_id], 
    [ps].[style_id] 
FROM 
    [dbo].[profile] [p], 
    [dbo].[profile_instruments] [pi], 
    [dbo].[profile_styles] [ps] 
WHERE 
    [p].[date_created] > DATEADD(yy, -2, GETDATE()) 
    AND [p].[shopper_id] = '53D5444535434747A935E207C9EDD96A' 
    AND [pi].[PID] = [p].[PID] 
    AND [ps].[PID] = [p].[PID] 
ORDER BY 
    [p].[shopper_id]; 
+0

乐器中的2个记录*每个配置文件的2个样式记录产生4个记录。我不明白这是怎么回事。 – xQbert

+0

[踢坏的习惯:使用旧式JOIN - Aaron Bertrand](http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/08/bad-habits-to-kick-using-old-style -joins.aspx) – SqlZim

+0

我认为'自然连接'实际上使用了单词'自然连接'和'使用'你在两个表中定义了同样命名的字段你想加入 – xQbert