SQL只返回来自左联接的不同ID

SQL只返回来自左联接的不同ID,sql,sql-server,database,Sql,Sql Server,Database,我继承了一些有趣的SQL,并试图找出如何消除具有重复ID的行。我们的索引以某种列格式存储,然后我们将所有行集中到一个列中,并将值作为不同的列 下面的示例返回三行唯一数据,但ID是重复的。我只需要两个具有唯一ID的行(以及与之配套的其他列)。我知道我会丢失一些数据,但我只需要每个ID为查询匹配一行(第一行、第一行、最早行、最新行等等) 我试过使用DISTINCT、GROUP BY和ROW_NUMBER,但我总是语法错误,或者在错误的地方使用它们 我还愿意以可重用的方式完全重写查询,因为我目前必须动

我继承了一些有趣的SQL,并试图找出如何消除具有重复ID的行。我们的索引以某种列格式存储,然后我们将所有行集中到一个列中,并将值作为不同的列

下面的示例返回三行唯一数据,但ID是重复的。我只需要两个具有唯一ID的行(以及与之配套的其他列)。我知道我会丢失一些数据,但我只需要每个ID为查询匹配一行(第一行、第一行、最早行、最新行等等)

我试过使用DISTINCT、GROUP BY和ROW_NUMBER,但我总是语法错误,或者在错误的地方使用它们

我还愿意以可重用的方式完全重写查询,因为我目前必须动态生成查询(cardtypes和CardIndex是用户定义的),并且希望能够创建一个存储过程。提前谢谢

declare @cardtypes table ([ID] int, [Name] nvarchar(50))
declare @cards table ([ID] int, [CardTypeID] int, [Name] nvarchar(50))
declare @cardindexes table ([ID] int, [CardID] int, [IndexType] int, [StringVal] nvarchar(255), [DateVal] datetime)

INSERT INTO @cardtypes VALUES (1, 'Funny Cards')
INSERT INTO @cardtypes VALUES (2, 'Sad Cards')

INSERT INTO @cards VALUES (1, 1, 'Bunnies')
INSERT INTO @cards VALUES (2, 1, 'Dogs')
INSERT INTO @cards VALUES (3, 1, 'Cat')
INSERT INTO @cards VALUES (4, 1, 'Cat2')

INSERT INTO @cardindexes VALUES (1, 1, 1, 'Bunnies', null)
INSERT INTO @cardindexes VALUES (2, 1, 1, 'playing', null)
INSERT INTO @cardindexes VALUES (3, 1, 2, null, '2014-09-21')
INSERT INTO @cardindexes VALUES (4, 2, 1, 'Dogs', null)
INSERT INTO @cardindexes VALUES (5, 2, 1, 'playing', null)
INSERT INTO @cardindexes VALUES (6, 2, 1, 'poker', null)
INSERT INTO @cardindexes VALUES (7, 2, 2, null, '2014-09-22')


SELECT TOP(100)
    [ID] = c.[ID],
    [Name] = c.[Name],
    [Keyword] = [colKeyword].[StringVal],
    [DateAdded] = [colDateAdded].[DateVal]
FROM @cards AS c
LEFT JOIN @cardindexes AS [colKeyword] ON [colKeyword].[CardID] = c.ID AND [colKeyword].[IndexType] = 1
LEFT JOIN @cardindexes AS [colDateAdded] ON [colDateAdded].[CardID] = c.ID AND [colDateAdded].[IndexType] = 2
WHERE [colKeyword].[StringVal] LIKE 'p%' AND c.[CardTypeID] = 1
ORDER BY [DateAdded]
编辑:

虽然这两种解决方案都有效,但我最终还是使用了@popovitsj中的MAX()解决方案,因为它更容易实现。对于我来说,来自多行的数据问题并没有真正考虑在内,因为所有行本质上都是同一条记录的一部分。我很可能会根据自己的需要使用这两种解决方案

以下是我更新的查询(因为它与答案不太匹配):


使用行数窗口函数和CTE可以很好地实现这一点。例如:

;With preResult AS (
SELECT TOP(100)
    [ID] = c.[ID],
    [Name] = c.[Name],
    [Keyword] = [colKeyword].[StringVal],
    [DateAdded] = [colDateAdded].[DateVal],
    ROW_NUMBER()OVER(PARTITION BY c.ID ORDER BY [colDateAdded].[DateVal]) rn
FROM @cards AS c
LEFT JOIN @cardindexes AS [colKeyword] ON [colKeyword].[CardID] = c.ID AND [colKeyword].[IndexType] = 1
LEFT JOIN @cardindexes AS [colDateAdded] ON [colDateAdded].[CardID] = c.ID AND [colDateAdded].[IndexType] = 2
WHERE [colKeyword].[StringVal] LIKE 'p%' AND c.[CardTypeID] = 1
ORDER BY [DateAdded]
)

SELECT * from preResult WHERE rn = 1

使用行数窗口函数和CTE可以很好地实现这一点。例如:

;With preResult AS (
SELECT TOP(100)
    [ID] = c.[ID],
    [Name] = c.[Name],
    [Keyword] = [colKeyword].[StringVal],
    [DateAdded] = [colDateAdded].[DateVal],
    ROW_NUMBER()OVER(PARTITION BY c.ID ORDER BY [colDateAdded].[DateVal]) rn
FROM @cards AS c
LEFT JOIN @cardindexes AS [colKeyword] ON [colKeyword].[CardID] = c.ID AND [colKeyword].[IndexType] = 1
LEFT JOIN @cardindexes AS [colDateAdded] ON [colDateAdded].[CardID] = c.ID AND [colDateAdded].[IndexType] = 2
WHERE [colKeyword].[StringVal] LIKE 'p%' AND c.[CardTypeID] = 1
ORDER BY [DateAdded]
)

SELECT * from preResult WHERE rn = 1

您可以使用MAX或MIN来“决定”重复行中其他列的显示内容

SELECT ID, MAX(Name), MAX(Keyword), MAX(DateAdded)
(...)
GROUP BY ID;

您可以使用MAX或MIN来“决定”重复行中其他列的显示内容

SELECT ID, MAX(Name), MAX(Keyword), MAX(DateAdded)
(...)
GROUP BY ID;

我还添加了orderbymax(DateAdded),以保持相同的顺序。事实上,我认为这个问题是重复的,虽然可以混合数据。。。使用id返回的行实际上可能与任何原始行都不匹配。是的,如果这是一个好的解决方案,这取决于具体的要求。@popovitsj我已经尝试过你的方法,它似乎有效。你能告诉我这与格林斯帕克建议的CTE/ROW_NUMBER()的利弊吗?另外,我不介意顺序,因为它们最终都是同一条记录的一部分,我只需利用多行数据即可。@JimBillig此解决方案的优点是可读性和性能更好。唯一的缺点正如Greenspark所提到的:它扰乱了数据:它可能从第1行获取关键字,从第2行获取DateAdded,以最大值为准。我还将按max添加ORDER(DateAdded)以保持相同的顺序。事实上,我认为这个问题是重复的,虽然可以混合数据。。。使用id返回的行实际上可能与任何原始行都不匹配。是的,如果这是一个好的解决方案,这取决于具体的要求。@popovitsj我已经尝试过你的方法,它似乎有效。你能告诉我这与格林斯帕克建议的CTE/ROW_NUMBER()的利弊吗?另外,我不介意顺序,因为它们最终都是同一条记录的一部分,我只需利用多行数据即可。@JimBillig此解决方案的优点是可读性和性能更好。唯一的缺点是Greenspark提到的:它扰乱了数据:它可能从第1行获取关键字,从第2行获取DateAdded,以最大值为准。这似乎有效。你能告诉我这样做的缺点是什么吗?这是一种在存在重复项的情况下从多行中选择一行的更好的技术,而不是最大值加上分组技术。MAX加上groupby技术可以很容易地实现两行或更多行的合并,用户不太可能希望或期望这样。如果他们希望并期望合并(我对此表示怀疑),则按路线进行最大/组。我经常使用ROW_NUMBER()代替。在DB2上,我们也可以使用横向连接来完成同样的事情,这是从许多行中选择一行的另一个优秀工具,但我认为SQL Server称之为不同的东西。你能告诉我这样做的缺点是什么吗?这是一种在存在重复项的情况下从多行中选择一行的更好的技术,而不是最大值加上分组技术。MAX加上groupby技术可以很容易地实现两行或更多行的合并,用户不太可能希望或期望这样。如果他们希望并期望合并(我对此表示怀疑),则按路线进行最大/组。我经常使用ROW_NUMBER()代替。在DB2上,我们也可以使用横向连接来完成同样的事情,这是从许多行中选择一行的另一个优秀工具,但我认为SQL Server称之为不同的东西。