2015-03-26 2 views
-1

В настоящее время мы обновляемся до SQL Server 2014; У меня есть соединение, которое отлично работает в SQL Server 2008 R2, но возвращает дубликаты в SQL Server 2014. Проблема связана с предикатом AND L2.ACCOUNTING_PERIOD = RG.PERIOD_TO, если я изменю его на все, кроме 4, я не получаю дубликатов. Запрос возвращает эти значения в отчетном периоде 4 дважды. Этот запрос получает сальдо счетов для всех предыдущих отчетных периодов, так что в этом случае она возвращает значения для отчетных периодов 0, 1, 2 и 3 правильно, но затем дублирует значение от периода 4.Слева от внешнего входа в SQL Server 2014

SELECT 
    A.ACCOUNT, 
    SUM(A.POSTED_TRAN_AMT), 
    SUM(A.POSTED_BASE_AMT), 
    SUM(A.POSTED_TOTAL_AMT) 
FROM 
    PS_LEDGER A 
    LEFT JOIN PS_GL_ACCOUNT_TBL B 
    ON B.SETID = 'LTSHR'      
    LEFT OUTER JOIN PS_LEDGER L2 
    ON A.BUSINESS_UNIT = L2.BUSINESS_UNIT 
     AND A.LEDGER = L2.LEDGER 
     AND A.ACCOUNT = L2.ACCOUNT          
     AND A.ALTACCT = L2.ALTACCT 
     AND A.DEPTID = L2.DEPTID 
     AND A.PROJECT_ID = L2.PROJECT_ID 
     AND A.DATE_CODE = L2.DATE_CODE 
     AND A.BOOK_CODE = L2.BOOK_CODE 
     AND A.GL_ADJUST_TYPE = L2.GL_ADJUST_TYPE 
     AND A.CURRENCY_CD = L2.CURRENCY_CD 
     AND A.STATISTICS_CODE = L2.STATISTICS_CODE 
     AND A.FISCAL_YEAR = L2.FISCAL_YEAR 
     AND A.ACCOUNTING_PERIOD = L2.ACCOUNTING_PERIOD 
     AND L2.ACCOUNTING_PERIOD = RG.PERIOD_TO 
WHERE 
    A.BUSINESS_UNIT  = 'UK001' 
    AND A.LEDGER   = 'LOCAL' 
    AND A.FISCAL_YEAR  = 2015 
    AND ((A.ACCOUNTING_PERIOD BETWEEN 1 and 4 
     AND B.ACCOUNT_TYPE IN ('E','R')) 
       OR 
     (A.ACCOUNTING_PERIOD BETWEEN 0 and 4 
     AND B.ACCOUNT_TYPE IN ('A','L','Q')) ) 
    AND A.STATISTICS_CODE = ' ' 
    AND A.ACCOUNT = '21101' 
    AND A.CURRENCY_CD <> ' ' 
    AND A.CURRENCY_CD = 'GBP' 
    AND B.SETID='LTSHR' 
    AND B.ACCOUNT=A.ACCOUNT 
    AND B.SETID = SETID 
    AND B.EFFDT=(SELECT MAX(EFFDT) FROM PS_GL_ACCOUNT_TBL WHERE SETID='LTSHR' AND WHERE ACCOUNT=B.ACCOUNT AND EFFDT<='2015-01-31 00:00:00.000') 
GROUP BY A.ACCOUNT 
ORDER BY A.ACCOUNT 
+8

Первое предположение о том, что данные отличаются в двух базах данных вы тестируете. –

+1

И, к сожалению, догадка, что он останется, без каких-либо DDL и DML, чтобы мы воспроизвели сценарий ... – Jeroen

+1

Обратите внимание, что, помещая предикаты равенства в предложение 'WHERE' для столбцов таблицы' B', вы эффективно конвертировали свой ' LEFT JOIN' этой таблицы во внутреннее соединение. Вероятно, это нормально, потому что условие соединения не полагается на левую таблицу вообще, так что это действительно кросс-соединение подмножества правой таблицы. –

ответ

0

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

Поскольку ваш запрос на самом деле не выбирает ничего из таблицы L2, и другие предикаты не полагаются на что-либо из этой таблицы, единственное, что достигнуто (слева), сводится к дублированию строк результатов предварительной агрегирования где более одного удовлетворяет условию соединения для той же строки L2. Это вряд ли будет тем, что вы хотите, особенно если это конкретное соединение является self, поэтому я не вижу причин не удалять его вообще. Доллары до пончиков, которые решают проблему дублирования.

Я также предлагаю удалить коррелированный подзапрос в предложении WHERE в пользу присоединения к встроенному виду, так как вы все равно присоединились к базовой таблице для подзапроса. Это конкретное встроенное представление использует версию оконной функции MAX() вместо версии функции агрегата. В идеале он будет напрямую выбирать только строки с целевыми значениями EFFDT, но он не может сделать этого, не будучи более сложным, и именно этого я и стараюсь избежать. Получающийся запрос поэтому фильтрует EFFDT внешне, как это сделал оригинал, но без коррелированного подзапроса.

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

Кроме того, поскольку вы фильтруете определенное значение A.ACCOUNT, это бессмысленно (но не так), чтобы GROUP BY или ORDER_BY этой колонке. Соответственно, я удалил эти предложения, чтобы сделать запрос более простым и понятным.

Вот что я придумал:

SELECT 
    A.ACCOUNT, 
    SUM(A.POSTED_TRAN_AMT), 
    SUM(A.POSTED_BASE_AMT), 
    SUM(A.POSTED_TOTAL_AMT) 
FROM 
    PS_LEDGER A 
    INNER JOIN (
     SELECT 
     *, 
     MAX(EFFDT) OVER (PARTITION BY ACCOUNT) AS MAX_EFFDT 
     FROM PS_GL_ACCOUNT_TBL 
     WHERE 
     EFFDT <= '2015-01-31 00:00:00.000' 
     AND SETID = 'LTSHR' 
    ) B 
    ON B.ACCOUNT=A.ACCOUNT 
WHERE 
    A.ACCOUNT = '21101' 
    AND A.BUSINESS_UNIT = 'UK001' 
    AND A.LEDGER   = 'LOCAL' 
    AND A.FISCAL_YEAR  = 2015 
    AND A.CURRENCY_CD = 'GBP' 
    AND A.STATISTICS_CODE = ' ' 
    AND B.EFFDT = B.MAX_EFFDT 
    AND CASE 
     WHEN B.ACCOUNT_TYPE IN ('E','R') 
     THEN A.ACCOUNTING_PERIOD BETWEEN 1 and 4 
     WHEN B.ACCOUNT_TYPE IN ('A','L','Q') 
     THEN A.ACCOUNTING_PERIOD BETWEEN 0 and 4 
     ELSE 0 
    END 
+0

О, мой. Спасибо! Оно работает!!!! – Amy