左外加入 SQL Server 2014
Left Outer Join in SQL Server 2014
我们目前正在升级到 SQL Server 2014;我有一个在 SQL Server 2008 R2 中运行良好但 returns 在 SQL Server 2014 中重复的连接。问题似乎与谓词 AND L2.ACCOUNTING_PERIOD = RG.PERIOD_TO
有关,因为如果我更改它除了 4,我没有得到重复项。查询在 Accounting Period 4 中两次返回这些值。此查询获取所有先前会计期间的帐户余额,因此在本例中,它 returns 会计期间 0、1、2 和 3 的值正确,但随后复制了期间 4 的值。
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
我倾向于怀疑您过于简化了原始查询以反映真正的问题,但我将根据到目前为止的评论回答所提出的问题。
由于您的查询实际上 select 没有从 table L2
派生的任何内容,也没有任何其他谓词依赖于 table 的任何内容,唯一的通过(左)连接完成它是复制预聚合结果的行,其中不止一个满足相同 L2
行的连接条件。这似乎不太可能是您想要的,尤其是那个特定的连接是 self 连接,所以我看不出有任何理由不完全删除它。 Dollars to doughnuts, 解决重复问题
我还建议删除 WHERE
子句中的相关子查询以支持加入内联视图,因为无论如何您已经加入子查询的基础 table。这个特定的内联视图使用 MAX()
的 window 函数版本而不是聚合函数版本。理想情况下,它会直接 select 只有具有目标 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
我们目前正在升级到 SQL Server 2014;我有一个在 SQL Server 2008 R2 中运行良好但 returns 在 SQL Server 2014 中重复的连接。问题似乎与谓词 AND L2.ACCOUNTING_PERIOD = RG.PERIOD_TO
有关,因为如果我更改它除了 4,我没有得到重复项。查询在 Accounting Period 4 中两次返回这些值。此查询获取所有先前会计期间的帐户余额,因此在本例中,它 returns 会计期间 0、1、2 和 3 的值正确,但随后复制了期间 4 的值。
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
我倾向于怀疑您过于简化了原始查询以反映真正的问题,但我将根据到目前为止的评论回答所提出的问题。
由于您的查询实际上 select 没有从 table L2
派生的任何内容,也没有任何其他谓词依赖于 table 的任何内容,唯一的通过(左)连接完成它是复制预聚合结果的行,其中不止一个满足相同 L2
行的连接条件。这似乎不太可能是您想要的,尤其是那个特定的连接是 self 连接,所以我看不出有任何理由不完全删除它。 Dollars to doughnuts, 解决重复问题
我还建议删除 WHERE
子句中的相关子查询以支持加入内联视图,因为无论如何您已经加入子查询的基础 table。这个特定的内联视图使用 MAX()
的 window 函数版本而不是聚合函数版本。理想情况下,它会直接 select 只有具有目标 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