SQL连接表仅在最高值上

时间:2018-09-20 10:12:18

标签: sql-server

我有两个连接在一起的表(在此示例中为Temp1和Temp2)。 Temp1中的某些ID具有链接到Temp2的多个ParentID,但我只希望实际返回1个ParentID。哪一个都不重要,所以我们只说Temp2中的最高值ID。

以下代码提供了一个很好的例子,说明了我从哪里开始

IF OBJECT_ID('tempdb..#Temp1') IS NOT NULL
    DROP TABLE #Temp1

IF OBJECT_ID('tempdb..#Temp2') IS NOT NULL
    DROP TABLE #Temp2

CREATE TABLE #Temp1
(
    ID INT
    ,ParentID INT
    ,Name VARCHAR(10)
)

CREATE TABLE #Temp2
(
    ID INT
    ,Name VARCHAR(15)
)

INSERT #Temp1 VALUES
(1, 1, 'Apples'),
(2, 1, 'Bananas'),
(3, 2, 'Milk'),
(3, 3, 'Milk'),
(4, 3, 'Wine'),
(4, 4, 'Wine')

INSERT #Temp2 VALUES
(1, 'Fruit'),
(2, 'Dairy'),
(3, 'Beverages'),
(4, 'Beer & Wine')

SELECT
T1.ID [ChildID]
,T1.Name [ChildName]
,T2.ID [ParentID]
,T2.Name [ParentName]
FROM #Temp1 T1
INNER JOIN #Temp2 T2 ON T2.ID = T1.ParentID

我想要的结果是:

ChildID     ChildName   ParentID    ParentName
1           Apples      1           Fruit
2           Bananas     1           Fruit
3           Milk        3           Beverages
4           Wine        4           Beer & Wine

我还看到了其他这样的示例,人们在其中使用了CROSS APPLY,但我似乎无法使其正常工作。感谢您的协助!

3 个答案:

答案 0 :(得分:1)

如下更改最终选择

;WITH CTE
AS
(
    SELECT
    RN = ROW_NUMBER() OVER(PARTITION BY T1.ID ORDER BY T1.Name),
    T1.ID [ChildID]
    ,T1.Name [ChildName]
    ,T2.ID [ParentID]
    ,T2.Name [ParentName]
    FROM #Temp1 T1
    INNER JOIN #Temp2 T2 ON T2.ID = T1.ParentID
)
SELECT
    [ChildID],
    [ChildName],
    [ParentID],
    [ParentName]
    FROM CTE
        WHERE RN = 1

答案 1 :(得分:1)

一种方法是将#Temp2表连接到cte,这是对#Temp1进行逐组查询的结果,该表针对id和name的每种组合都包含一行,并带有min (或最大)父ID:

;WITH CTETemp1 AS
(
    SELECT ID, Min(ParentID) As PID, Name
    FROM #Temp1
    GROUP BY ID, Name
)

SELECT   T1.ID [ChildID]
        ,T1.Name [ChildName]
        ,T2.ID [ParentID]
        ,T2.Name [ParentName]
FROM CTETemp1 AS T1 
JOIN #Temp2 AS T2 ON T1.PID = T2.ID

顺便说一句,这种关系被称为多对多关系,应该通过添加一个新表将#temp1#temp2的ID链接在一起来实现它-这样看起来会更好像这样:

CREATE TABLE #Temp1
(
    ID INT
    ,Name VARCHAR(10)
)

CREATE TABLE #Temp2
(
    ID INT
    ,Name VARCHAR(15)
)

CREATE TABLE #Temp1ToTemp2
(
    ID1,
    ID2,
    PRIMARY KEY(ID1, ID2)
)

INSERT #Temp1 VALUES
(1, 'Apples'),
(2, 'Bananas'),
(3, 'Milk'),
(4, 'Wine'),

INSERT #Temp2 VALUES
(1, 'Fruit'),
(2, 'Dairy'),
(3, 'Beverages'),
(4, 'Beer & Wine')

INSERT INTO #Temp1ToTemp2 (ID1, ID2) VALUES
(1,1), (2, 1), (3, 2), (3, 3), (4, 3), (4, 4)

主要优点是现在您的数据库中没有重复的数据了。

答案 2 :(得分:0)

您的结构破坏了数据库的正常形式。您显然具有多对多关系。我建议您重新设计表结构。就像您现在拥有的那样,表#Temp1不在每一行中存储有关产品的信息,而是每行都呈现与#Temp2的关系。

#Temp1中的每个ID只能有一行。为简单起见,我省略了主键和外键约束:

CREATE TABLE #Temp1 (
  ID INT,
  Name VARCHAR(10)
)

CREATE TABLE #Temp2 (
  ID INT,
  Name VARCHAR(15)
)

CREATE TABLE #TempRelation (
  ID_Temp1 INT,
  ID_Temp2 INT
)

关键概念是将temp1和temp2之间的每个关系存储在单独的表#TempRelation中。

要填充这些表,您需要将INSERT语句更改为:

INSERT #Temp1 VALUES
(1, 'Apples'),
(2, 'Bananas'),
(3, 'Milk'),
(4, 'Wine')

INSERT #TempRelation VALUES
(1,1),
(2,1),
(3,2),
(3,3),
(4,3),
(4,4)

然后您的查询就这么简单:

SELECT
  tr.id_temp1 as childid,
  t1.name as childname,
  tr.id_temp2 as parentid,
  t2.name as parentname,
FROM (
  SELECT id_temp1, max(id_temp2) as id_temp2
  FROM #TempRelation tr
  GROUP BY id_temp1
) tr
JOIN #Temp1 t1 ON tr.id_temp1 = t1.id
JOIN #Temp2 t2 ON tr.id_temp2 = t2.id