SQL返回重复的结果

时间:2011-07-29 17:18:54

标签: sql sql-server-2008 join

为什么以下SQL查询会返回重复的结果?我只想在结果集中返回3行。我猜我的连接不正确。约束应该从查询连接中解释。如果您需要其他信息,请询问。

SELECT 
    [addresstype].name As [Type], 
    [address].city As [City], address.statecode As [State], 
    [address].postalcode As [Zip], 
    [address].addressid As [Id] 
FROM  
    [address]
    LEFT OUTER JOIN [contact_address] ON [address].addressid = [contact_address].addressid 
    LEFT OUTER JOIN [addresstype] ON [addresstype].addresstypeid = [contact_address].addresstypeid 
    LEFT OUTER JOIN [clientcontact] ON dbo.contact_address.contactid = [clientcontact].contactid 
WHERE  
    [contact_address].contactid = 12538 
ORDER BY 
    [address].name, [address].statecode, [address].city  

结果:

enter image description here

======================

更多信息

看起来我有多个客户端。我有这个连接的原因不是这个查询,而是另一个依赖于这个查询的查询。它是在.NET代码中定制的规则引擎中构建的。另一个查询需要此clientcontact连接,因为有一个临时表是从UNION查询构建的。如果是这种情况,我真的不需要这个表(clientcontact)与该连接。我得到多行,因为我在clientcontact表中有多个clientid。换句话说,此联系人适用于所有这些客户。但是,我想放入一个WHERE子句,所以我得到3行,但我不能搞乱JOINS。根据我上面的解释,这些是共享的。如何才能做到这一点? ...原谅我的正确加入..不应该改变任何事情。不要让那些让你困惑。 : - )

新查询显示:

SELECT 
    dbo.clientcontact.clientcontactid ,
    dbo.clientcontact.clientid ,
    dbo.clientcontact.contactid
    --[addresstype].name As [Type], 
    --[address].city As [City], address.statecode As [State], 
    --[address].postalcode As [Zip], 
    --[address].addressid As [Id] 
FROM  
    [address]
    LEFT OUTER JOIN [contact_address] ON [address].addressid = [contact_address].addressid 
    LEFT OUTER JOIN [addresstype] ON [addresstype].addresstypeid = [contact_address].addresstypeid 
    right JOIN [clientcontact] ON dbo.contact_address.contactid = [clientcontact].contactid 
WHERE  
    [contact_address].contactid = 12538 
ORDER BY 
    [address].name, [address].statecode, [address].city  

enter image description here

=================

更多更新

有些人对我为什么无法删除clientcontact连接感到困惑。这是因为我们的.NET规则引擎中的另一个查询正在使用同一个查询。请参阅下面的UNION查询的第二个查询。如果通过保持连接绝对没有办法从中获得3行,那么这就是我猜的答案。然后我需要将两者分开。

SELECT 
    client_addressexternal.address_table_type As [Address Record Type], 
    addresstype.name As [Type], 
    CASE WHEN client_addressexternal.address_table_type = 'CLIENT Address' THEN '<a href="/ClientServices/ManageClients/ClientDetails/ClientAddresses.aspx?Id=' + CONVERT(VARCHAR,client_addressexternal.addressid) + '&ClientId=' + CONVERT(VARCHAR,client_addressexternal.client_id) + '&SourceClientId=14103">' + address.name + '</a>' + '<br /><b>Client Name:</b> ' + client_addressexternal.client_full_name ELSE client_addressexternal.contact_full_name END As [Address Name], 
    dbo.limssubstring(dbo.LIMSNullString(address1) + '<br />' + dbo.LIMSNullString(address2), 84) As [Address], 
    address.city As [City], address.statecode As [State], 
    address.postalcode As [Zip], 
    CASE client.clientid WHEN 14103 THEN '' ELSE client.name END As [From Parent Client], 
    address.addressid As [Id] 
FROM  
address 
    JOIN (

        SELECT client_address.clientid, client_address.addressid, client_address.addresstypeid, depth, 'CLIENT Address' AS 'address_table_type', '' as 'contact_full_name', client.name as 'client_full_name', client_address.clientid as 'client_id', '' as 'contact_id'
        FROM dbo.fnClientRelatives(14103, 0, 1, 0) relatives
        inner join client_address on client_address.clientid = relatives.clientid
        LEFT OUTER JOIN client ON relatives.clientid = dbo.client.clientid

        UNION

        SELECT clientcontact.clientid, contact_address.addressid, contact_address.addresstypeid, 999 [depth], 'CONTACT Address' AS 'address_table_type', address.name + '<br /><b>Contact Name:</b> ' + LTRIM(RTRIM(ISNULL(contact.firstname, '') + ISNULL(' ' + contact.middleinitial + ' ', ' ') + ISNULL(contact.lastname, ''))), '' as 'client_full_name', clientcontact.clientid as 'client_id', clientcontact.contactid as 'contact_id'
        from clientcontact 
        inner join contact_address ON contact_address.contactid=clientcontact.contactid and clientcontact.clientid=14103
        LEFT OUTER JOIN [contact] ON [clientcontact].contactid = [contact].contactid
        LEFT OUTER JOIN [address] ON contact_address.addressid = address.addressid

    ) AS client_addressexternal ON client_addressexternal.addressid = address.addressid 
    JOIN client ON client.clientid = client_addressexternal.clientid 
    JOIN addresstype on addresstype.addresstypeid = client_addressexternal.addresstypeid 
 ORDER BY 
    depth,address.statecode, address.city, address.name     

如果您对此感兴趣,可以使用以下功能:

GO
/****** Object:  UserDefinedFunction [dbo].[fnClientRelatives]    Script Date: 07/29/2011 12:48:24 ******/
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER ON
GO
--your basic recursive tree searcher.
--childrennotparents = 1 means you'll get children. = 0 means you'll get parents
--@recursive = 1 means it finds all children, grandchildren, etc... or whatever
-- The depth is the base level to start incrementing each level, if set to zero, the @clientid will also be part of the results
ALTER  FUNCTION [dbo].[fnClientRelatives]
(
    @clientId INT,
    @childrenNotParents BIT,
    @recursive bit,
    @depth int
)
RETURNS @clientids TABLE (clientid INT primary key clustered, depth int)
AS
begin

-- Add the parent client id if the depth is zero
if @depth = 0
begin
    INSERT INTO @clientids VALUES (@clientid, @depth)
end
set @depth = @depth + 1

IF @childrenNotParents = 1  
begin
    DECLARE clientids CURSOR FOR  
        SELECT clientid
        FROM client
        where parentclientid = @clientId
END--/if childrennotparents
ELSE--if not childrennotparents  
BEGIN  
    DECLARE clientids CURSOR FOR  
        SELECT parentclientid
        FROM client
        where clientid = @clientid
END--/if not childrennotparents

OPEN clientids
DECLARE @nextClientID INT
FETCH clientids INTO @nextClientID
--@nextClientID may be null if we're loading parents, and the
--current client has null for a parent id.
WHILE @@FETCH_STATUS = 0 AND @nextClientID IS NOT NULL
BEGIN  
    INSERT INTO @clientids
    VALUES (@nextclientid, @depth)

    IF @recursive = 1  
    BEGIN  
        INSERT INTO @clientids  
            SELECT * FROM dbo.fnClientRelatives(@nextclientid, @childrenNotParents, @recursive, @depth)    
    END--IF @recursive = 1    
FETCH clientids INTO @nextclientid  
END--WHILE @@FETCH_STATUS = 0  

CLOSE clientids  
DEALLOCATE clientids  

RETURN   
END--/IssueRelatives

地址数据库图表:

enter image description here

6 个答案:

答案 0 :(得分:7)

更多信息会有所帮助,但根据您提供的内容,我会说您在 clientcontact 表中有多条记录。

DISTINCT关键字添加到您的select语句中或删除不必要的联接(您没有使用 clientcontact 表中的任何内容)。

注意:很多人使用DISTINCT关键字来掩盖写得不好的查询。虽然DISTINCT会为您提供您期望的结果,但它并没有真正解决您的问题 - 它会掩盖它。在考虑使用DISTINCT之前,请务必了解为什么获取重复记录。

修改

如果你无法删除联接(仍然不确定我理解为什么),DISTINCT不起作用(仍不确定我明白为什么),那么添加GROUP BY

GROUP BY [addresstype].name,
         [address].city,
         [adress].statecode,
         [address].postalcode,
         [address].addressid 

答案 1 :(得分:5)

在SELECT

之后添加DISTINCT
SELECT DISTINCT
    [addresstype].name As [Type], 
    [address].city As [City], address.statecode As [State], 
    [address].postalcode As [Zip], 
    [address].addressid As [Id],
    [address].name
FROM  
    [address]
    LEFT OUTER JOIN [contact_address] ON [address].addressid = [contact_address].addressid 
    LEFT OUTER JOIN [addresstype] ON [addresstype].addresstypeid = [contact_address].addresstypeid 
    LEFT OUTER JOIN [clientcontact] ON dbo.contact_address.contactid = [clientcontact].contactid 
WHERE  
    [contact_address].contactid = 12538 
ORDER BY 
    [address].name, [address].statecode, [address].city  

将[address] .name添加到SELECT列表中以超越您获得的ORDER BY错误

答案 2 :(得分:5)

您需要SELECT DISTINCT,因为关系数据库基于多集(尽管关系数据模型基于集合)。

答案 3 :(得分:5)

您可以使用Select distinct但是您必须添加[address] .name列来选择这样的列表(或者您可以从orderby子句中删除[address] .name列。:

SELECT DISTINCT
[address].name as [Address],
    [addresstype].name As [Type], 
    [address].city As [City], address.statecode As [State], 
    [address].postalcode As [Zip], 
    [address].addressid As [Id] 
FROM  
    [address]
    LEFT OUTER JOIN [contact_address] ON [address].addressid = [contact_address].addressid 
    LEFT OUTER JOIN [addresstype] ON [addresstype].addresstypeid = [contact_address].addresstypeid 
    LEFT OUTER JOIN [clientcontact] ON dbo.contact_address.contactid = [clientcontact].contactid 
WHERE  
    [contact_address].contactid = 12538 
ORDER BY 
    [address].name, [address].statecode, [address].city

它应该可以工作,但您可能想要重写您的查询。为此,您能否为您的数据库提供表映射,以便我们提供帮助?

答案 4 :(得分:5)

添加where子句不太可能为您提供所需的结果。

我对你描述的限制你搞乱连接的能力的情况感到有点困惑,但是一个分组是我能想到的唯一可行的选择。

GROUP BY ([addresstype].name,[address].city,
           address.statecode,[address].postalcode,[address].addressid)

答案 5 :(得分:3)

了解为什么从查询中获取多个重复行是学习SQL的关键技能 - 也是我建议使用SELECT *而不是使用列列表。

一旦您查看整个(宽)结果集,您就可以确定整个结果集包含差异的位置(即使仅包含5列的投影结果集看起来相同)。只有通过检查这些差异,您才能确定如何更新原始查询: - 通过向WHERE子句添加条件,向ON的{​​{1}}子句之一添加条件,或引入可以减少结果集的新JOIN