SQL возвращает повторяющиеся результаты - PullRequest
7 голосов
/ 29 июля 2011

Почему следующий запрос 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. Другими словами, этот контакт работает на всех этих клиентов. Тем не менее, я хотел бы добавить предложение 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

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

Больше обновлений

Некоторые были смущены тем, почему я не могу удалить соединение клиент-контакт. Это потому, что другой запрос в нашем механизме правил .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 ]

7 голосов
/ 29 июля 2011

Было бы полезно получить дополнительную информацию, но, исходя из того, что вы предоставили, я бы сказал, что у вас есть несколько записей в таблице clientcontact .

Добавьте ключевое слово DISTINCT в оператор выбора или удалите ненужное объединение (вы ничего не используете из таблицы clientcontact ).

ПРИМЕЧАНИЕ: Многие люди используют ключевое слово DISTINCT, чтобы скрыть плохо написанный запрос. В то время как DISTINCT даст вам ожидаемые результаты, на самом деле это не решит вашу проблему - она ​​ее закроет. Прежде чем подумать об использовании DISTINCT.

, убедитесь, что вы понимаете , почему вы получаете дублирующиеся записи.

EDIT:

Если вы не можете удалить соединение (все еще не уверены, что я понимаю, почему), и DISTINCT не работает (все еще не уверены, что я понимаю, почему), тогда добавьте GROUP BY

GROUP BY [addresstype].name,
         [address].city,
         [adress].statecode,
         [address].postalcode,
         [address].addressid 
5 голосов
/ 29 июля 2011

Добавление предложения where вряд ли даст вам результат, который вы ищете.

Меня немного смущает описанная вами ситуация, ограничивающая вашу возможность связываться с объединениями, но единственная жизнеспособная опция, о которой я могу подумать, - это группировка по.

GROUP BY ([addresstype].name,[address].city,
           address.statecode,[address].postalcode,[address].addressid)
5 голосов
/ 29 июля 2011

Вы можете использовать Select distinct Но вам нужно будет добавить столбец [адрес] .name, чтобы выбрать такой список (в качестве альтернативы, вы можете удалить столбец [адрес] .name из вашего предложения orderby ::100100 *

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

это должно сработать, но вы, вероятно, захотите переписать свой запрос. Чтобы сделать это, не могли бы вы предоставить сопоставления таблиц для вашей базы данных, чтобы мы могли помочь?

5 голосов
/ 29 июля 2011

Вам нужен SELECT DISTINCT, потому что реляционные базы данных основаны на мультимножествах (хотя реляционная модель данных основана на наборах).

5 голосов
/ 29 июля 2011

Добавьте DISTINCT после того, как ваш SELECT

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  

добавил [адрес] .name в список SELECT, чтобы обойти ошибку ORDER BY, которую вы получали

3 голосов
/ 29 июля 2011

Понимание почему вы получаете несколько повторяющихся строк из запроса - это важный навык для изучения SQL - и это одно из немногих мест, где я бы рекомендовал использовать SELECT * вместо использования столбцаlist.

После просмотра всего (широкого) набора результатов можно надеяться определить, где весь набор результатов содержит различия (даже если прогнозируемый набор результатов, содержащий только 5 столбцов, выглядит идентичным).Только путем изучения этих различий вы можете определить, как обновить исходный запрос: - либо добавив условия к предложению WHERE, либо добавив условия к одному из предложений ON в JOIN, либо введя новый JOIN, что может уменьшить набор результатов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...