Sybase SQL — удаление полудубликатов из результатов запроса

У меня есть запрос, в котором используются два оператора SELECT, объединенные с помощью оператора UNION ALL. Оба оператора извлекают данные из похожих таблиц для заполнения результатов запроса. Я пытаюсь удалить «полудублирующиеся» строки из запроса, но у меня возникают проблемы с этим.

Мой запрос следующий:

    SELECT DISTINCT * 
FROM
    (
    SELECT
        TeamNum = CASE 
                WHEN T.TeamName = 'Alpha Team'
                    THEN '1'
                WHEN T.TeamName IN ('Bravo Team', 'Charlie Team')
                    THEN '2'
                WHEN T.TeamName = 'Delta Team'
                    THEN '3'
                ELSE '<Undefined>'
                END,
        P.PatientLastName AS LastName,
        P.PatientFirstName AS FirstName,
        R.PrimaryCity AS City,
        ReimbursorName = CASE
                WHEN RE.ReimbursorDescription = 'Medicare'
                    Then 'R1'
                WHEN RE.ReimbursorDescription = 'Medicaid'
                    Then 'R2'
                ELSE 'R3'
                END,
        P.PatientID AS PatientID
    FROM 
        PatReferrals PR LEFT JOIN Patient P ON PR.PatientID = P.PatientID,
        Patient P LEFT OUTER JOIN Rolodex R ON P.RolodexID = R.RolodexID,
        PatReferrals PR LEFT OUTER JOIN PatReimbursors PRE ON PR.PatientID = PRE.PatientID,
        PatReimbursors PRE LEFT OUTER JOIN Reimbursors RE ON PRE.ReimbursorID = RE.ReimbursorID,
        PatReferrals PR FULL OUTER JOIN Teams T ON PR.TeamID = T.TeamID,
    WHERE 
        PR.ReferralDate BETWEEN GETDATE()-4 AND GETDATE()-1
        AND PR.Status <> 'R' 
        AND PRE.CoveragePriority = '1'
        AND PRE.ExpirationDate IS NULL 

    UNION ALL

    SELECT
        TeamNum = CASE 
                WHEN T.TeamName = 'Alpha Team'
                    THEN '1'
                WHEN T.TeamName IN ('Bravo Team', 'Charlie Team')
                    THEN '2'
                WHEN T.TeamName = 'Delta Team'
                    THEN '3'
                ELSE '<Undefined>'
                END,
        P.PatientLastName AS LastName,
        P.PatientFirstName AS FirstName,
        R.PrimaryCity AS City,
        ReimbursorName = CASE
                WHEN RE.ReimbursorDescription = 'Medicare'
                    Then 'E1'
                WHEN RE.ReimbursorDescription = 'Medicaid'
                    Then 'E2'
                ELSE 'E3'
                END,
        P.PatientID AS PatientID
    FROM 
        PatReferrals PR LEFT JOIN Patient P ON PR.PatientID = P.PatientID,
        Patient P LEFT OUTER JOIN Rolodex R ON P.RolodexID = R.RolodexID,
        PatReferrals PR LEFT OUTER JOIN PatEligibilities PE ON PR.PatientID = PE.PatientID,
        PatEligibilities PE LEFT OUTER JOIN Reimbursors RE ON PE.ReimbursorID = RE.ReimbursorID,
        PatReferrals PR FULL OUTER JOIN Teams T ON PR.TeamID = T.TeamID,
    WHERE 
        PR.ReferralDate BETWEEN GETDATE()-4 AND GETDATE()-1
        AND PR.Status <> 'R' 
        AND PE.Status <> 'V'
        AND PE.ApplicationDate BETWEEN DATE(PR.ReferralDate)-5 AND DATE('2100/01/01')
    ) 

AS DUMMYTBL

ORDER BY 
    DUMMYTBL.LastName ASC,
    DUMMYTBL.FirstName ASC

Результаты, которые я получаю при выполнении запроса, следующие:

3   Doe Jane    Town    R1  19874
1   Roe John    City    R3  50016
1   Roe John    City    E1  50016
2   Smith   Jane    Town    E3  33975

Данные, которые мне нужно удалить, представляют собой повторяющиеся строки на основе определенных критериев после того, как результаты будут получены из исходного запроса. Каждый человек может быть указан только один раз, и у него должен быть один источник оплаты (R1, R2, R3, E1, E2, E3). Если есть R#, то для этого человека не может быть указано E#. Если нет R#, то должен быть указан E#. Как показано в моем примере, в строках 2 и 3 указан один и тот же человек, но два источника оплаты (R3 и E1).

Как я могу сделать так, чтобы у каждого человека отображалась только одна строка, используя критерии, которые я перечислил?

EDIT: изменен запрос SQL, чтобы показать исходные переменные из предложений WHERE, чтобы показать дополнительные сведения о запросе. Таблицы PatReimbursors и PatEligibilities содержат схожие данные, но используются разные критерии для извлечения правильных данных.


person Mr Xaero    schedule 21.03.2013    source источник
comment
TeamNum = T.TeamName,? Это опечатка?   -  person Rachcha    schedule 21.03.2013
comment
Это действительно рабочий запрос? Предложения from, по-видимому, имеют несколько вхождений одних и тех же псевдонимов - похоже, что это никогда не может быть запущено. Кроме того, если имеется несколько источников «R», какой из них имеет приоритет?   -  person    schedule 21.03.2013
comment
@Rachcha - я сократил эту часть запроса, так как изначально это был оператор CASE для возврата чисел из TeamName. @Mark Bannister - Да, этот запрос действительно работает.   -  person Mr Xaero    schedule 21.03.2013


Ответы (3)


Ваш запрос не имеет смысла. Я бы начал с устранения неявного декартова произведения, созданного , в предложении from.

Я предполагаю, что предложение from должно быть:

FROM 
    PatReferrals PR LEFT JOIN
    Patient P
    ON PR.PatientID = P.PatientID left outer join
    Rolodex R
    ON P.RolodexID = R.RolodexID left outer join
    PatEligibilities PE
    ON PR.PatientID = PE.PatientID left outer join
    Reimbursors RE
    ON PE.ReimbursorID = RE.ReimbursorID left outer join
    Teams T ON PR.TeamID = T.TeamID

Как только вы это сделаете, вам может не понадобиться union all или select distinct. Возможно, вы сможете поместить в один и тот же запрос как возмещающие расходы, так и права.

person Gordon Linoff    schedule 21.03.2013
comment
Таблица PatReferrals разветвляется как на PatReimbursors, так и на PatEligibilities. Чтобы получить оба значения для заполнения в одном запросе, необходимо было вставить UNION из двух похожих операторов SELECT. Без этого я бы получил данные либо от PatReimbursors, либо от PatEligibilities, но не от обоих. - person Mr Xaero; 21.03.2013
comment
Это нормально. Это предотвращает один тип декартова произведения. Однако вы ввели несколько других, включив ,s в предложение from. - person Gordon Linoff; 21.03.2013

Используйте подзапрос или подзапросы.

Общий запрос должен быть написан с использованием следующего шаблона:

 Select Distinct [Person Data]
 From PersonTable
     left Join to otherTable1 -- add outer join for each table you need data from
         On [Conditions that ensure join can generate only one row per person,
               ... and specify which of possibly many rows to get...]

Убедитесь, что условия исключают любую возможность объединения для создания более одной строки из другой [внешней] таблицы для каждой строки пользователя в таблице person. Это может (и часто) требовать, чтобы условие соединения основывалось на подзапросе, как, например...

 Select Distinct [Person Data]
 From PersonTable p
     left Join to employments e -- add outer join for each table you need data from
         On e.PersonId = p.PersonId 
            and e.HireDate = (Select Max(hiredate) from employments
                              where personId = p.PersonId)
person Charles Bretana    schedule 21.03.2013

Поработав с этим некоторое время сегодня, я нашел решение проблемы, с которой я столкнулся. Вот решение, которое работает и извлекает правильную информацию, которая мне была нужна:

SELECT DISTINCT 
    TeamNum,
    LastName,
    FirstName,
    City,
    ReimbursorName = CASE
        WHEN max(ReimbursorName) IN ('R1', 'E1')
            THEN '1' 
        WHEN max(ReimbursorName) IN ('R2', 'E2')
            THEN '2'
        ELSE '3'
        END,
    PatientID 
FROM
    (
    SELECT
        TeamNum = CASE 
                WHEN T.TeamName = 'Alpha Team'
                    THEN '1'
                WHEN T.TeamName IN ('Bravo Team', 'Charlie Team')
                    THEN '2'
                WHEN T.TeamName = 'Delta Team'
                    THEN '3'
                ELSE '<Undefined>'
                END,
        P.PatientLastName AS LastName,
        P.PatientFirstName AS FirstName,
        R.PrimaryCity AS City,
        ReimbursorName = CASE
                WHEN RE.ReimbursorDescription = 'Medicare'
                    Then 'R1'
                WHEN RE.ReimbursorDescription = 'Medicaid'
                    Then 'R2'
                ELSE 'R3'
                END,
        P.PatientID AS PatientID
    FROM 
        PatReferrals PR LEFT JOIN Patient P ON PR.PatientID = P.PatientID,
        Patient P LEFT OUTER JOIN Rolodex R ON P.RolodexID = R.RolodexID,
        PatReferrals PR LEFT OUTER JOIN PatReimbursors PRE ON PR.PatientID = PRE.PatientID,
        PatReimbursors PRE LEFT OUTER JOIN Reimbursors RE ON PRE.ReimbursorID = RE.ReimbursorID,
        PatReferrals PR FULL OUTER JOIN Teams T ON PR.TeamID = T.TeamID
    WHERE 
        PR.ReferralDate BETWEEN GETDATE()-4 AND GETDATE()-1
        AND PR.Status <> 'R' 
        AND PRE.CoveragePriority = '1'
        AND PRE.ExpirationDate IS NULL 

    UNION ALL

    SELECT
        TeamNum = CASE 
                WHEN T.TeamName = 'Alpha Team'
                    THEN '1'
                WHEN T.TeamName IN ('Bravo Team', 'Charlie Team')
                    THEN '2'
                WHEN T.TeamName = 'Delta Team'
                    THEN '3'
                ELSE '<Undefined>'
                END,
        P.PatientLastName AS LastName,
        P.PatientFirstName AS FirstName,
        R.PrimaryCity AS City,
        ReimbursorName = CASE
                WHEN RE.ReimbursorDescription = 'Medicare'
                    Then 'E1'
                WHEN RE.ReimbursorDescription = 'Medicaid'
                    Then 'E2'
                ELSE 'E3'
                END,
        P.PatientID AS PatientID
    FROM 
        PatReferrals PR LEFT JOIN Patient P ON PR.PatientID = P.PatientID,
        Patient P LEFT OUTER JOIN Rolodex R ON P.RolodexID = R.RolodexID,
        PatReferrals PR LEFT OUTER JOIN PatEligibilities PE ON PR.PatientID = PE.PatientID,
        PatEligibilities PE LEFT OUTER JOIN Reimbursors RE ON PE.ReimbursorID = RE.ReimbursorID,
        PatReferrals PR FULL OUTER JOIN Teams T ON PR.TeamID = T.TeamID
    WHERE 
        PR.ReferralDate BETWEEN GETDATE()-4 AND GETDATE()-1
        AND PR.Status <> 'R' 
        AND PE.Status <> 'V'
        AND PE.ApplicationDate BETWEEN DATE(PR.ReferralDate)-5 AND DATE('2100/01/01')
    ) 

AS DUMMYTBL
GROUP BY
    TeamNum,
    LastName,
    FirstName,
    City,
    PatientID
ORDER BY 
    DUMMYTBL.LastName ASC,
    DUMMYTBL.FirstName ASC

Спасибо за все предоставленные ответы.

person Mr Xaero    schedule 21.03.2013