如何正确加入和组合

时间:2017-06-28 19:48:47

标签: sql-server-2012 group-by duplicates inner-join

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

我的第一个查询使用了表格配置文件和tabe工具:

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

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

也许......

我们为每个PID的每个样式和工具分配一个行号。然后我们不仅通过PID加入,我们通过Row_number加入,它保证当pID有2个乐器和两个样式时,我们仍然只获得2个记录;而不是4。

使用全外连接,因为我不知道您是否希望看到存在2个乐器但仅存在1种风格或2种风格但只有1种乐器的情况。

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或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的所有记录,你仍然会在一张桌子上得到空。

答案 1 :(得分: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];