不要重复自己:相同的 SQL 查询,但有两个不同的表
Posted
技术标签:
【中文标题】不要重复自己:相同的 SQL 查询,但有两个不同的表【英文标题】:Don't repeat yourself: same SQL query, but two different tables 【发布时间】:2013-04-12 12:18:42 【问题描述】:我有一个 SQL 查询,其代码完全相同,但有两个不同的表(AUDIT_TRAIL_ARCHIVE 和 AUDIT_TRAIL)。我使用“UNION ALL”得到一个结果。
优秀的程序员使用"Don't repeat yourself" 原则。优秀的程序员会避免 WET(所有内容都写两次)。
如何按照“不要重复自己”的原则重写这段代码?
SELECT REPLACE (ENTITY_KEY, 'rss_user_name=CN=', '')
FROM AUDIT_TRAIL_ARCHIVE AU
INNER JOIN
(SELECT RSS_USER_NAME
FROM RSS_USER
WHERE RSS_NAME = 'rmad'
AND ADD_INFO_MASTER LIKE '%__47__UPN=%@richemont.com%') FALSCH
ON REPLACE (AU.ENTITY_KEY, 'rss_user_name=CN=', '') =
FALSCH.RSS_USER_NAME
WHERE AU.RSS_NAME = 'rmad'
AND AU.TABLE_NAME = 'rss_user'
AND AU.ACTION = 'Insert'
AND AU.ENTITY_KEY LIKE 'rss_user_name=CN=%'
AND AU.ORIGIN != 'RSS'
UNION ALL
SELECT REPLACE (ENTITY_KEY, 'rss_user_name=CN=', '')
FROM AUDIT_TRAIL AU
INNER JOIN
(SELECT RSS_USER_NAME
FROM RSS_USER
WHERE RSS_NAME = 'rmad'
AND ADD_INFO_MASTER LIKE '%__47__UPN=%@richemont.com%') FALSCH
ON REPLACE (AU.ENTITY_KEY, 'rss_user_name=CN=', '') =
FALSCH.RSS_USER_NAME
WHERE AU.RSS_NAME = 'rmad'
AND AU.TABLE_NAME = 'rss_user'
AND AU.ACTION = 'Insert'
AND AU.ENTITY_KEY LIKE 'rss_user_name=CN=%'
AND AU.ORIGIN != 'RSS'
【问题讨论】:
你的目标是什么:使用动态 sql,例如相同的 sql 但不同。表还是像 Florin 的示例那样重写查询? @fyodor78 第一个解决方案并不总是最好的。当然,您可以在选择之前加入表 - 但是当您想从每个表中检索一行时,为什么要构建一个 100.000 行的临时表?请参阅动态 SQL,创建一个过程,构建一个查询字符串并重用该过程。 【参考方案1】:例如:
SELECT REPLACE (ENTITY_KEY, 'rss_user_name=CN=', '')
FROM (select * --or relevant columns
from AUDIT_TRAIL_ARCHIVE AU
union all
select *
from AUDIT_TRAIL AU
) AU
INNER JOIN
(SELECT RSS_USER_NAME
FROM RSS_USER
WHERE RSS_NAME = 'rmad'
AND ADD_INFO_MASTER LIKE '%__47__UPN=%@richemont.com%') FALSCH
ON REPLACE (AU.ENTITY_KEY, 'rss_user_name=CN=', '') =
FALSCH.RSS_USER_NAME
WHERE AU.RSS_NAME = 'rmad'
AND AU.TABLE_NAME = 'rss_user'
AND AU.ACTION = 'Insert'
AND AU.ENTITY_KEY LIKE 'rss_user_name=CN=%'
AND AU.ORIGIN != 'RSS'
【讨论】:
我认为您无法通过其余查询中的值过滤您UNION ALL
的两个选择是否正确?
没有。实际上,答案过滤了 where 子句中的两个查询:AU.TABLE_NAME = 'rss_user'
。 AU 是 union all 部分的别名。过滤器可以在执行join之前由引擎推送过滤。【参考方案2】:
只是你不能。 SQL 是编译语言 (即使它看起来像脚本),Oracle 会记住查询所依赖的 OBJECT_ID。查询的每一半都有不同的依赖关系、不同的“字节码”和不同的执行计划。
你可以
使用表空间分区。那么你将只有一张桌子。可以使用“select * from AUDIT_TRAIL partition ACTIVE”限制对实时数据的查询。
像这样使用查询因子
WITH AU AS
(SELECT * from AUDIT_TRAIL union all select * from AUDIT_TRAIL_ARCHIVE)
SELECT REPLACE (ENTITY_KEY, 'rss_user_name=CN=', '')
FROM AU JOIN ...
...
但我不确定在这种情况下 Oracle 是否会保证执行计划的相同效率。
【讨论】:
【参考方案3】:优秀的程序员使用“不要重复自己”的原则。优秀的程序员会避免 WET(所有内容都写两次)。
呵呵。我喜欢。微妙的。
另外,我可能太基础了,但我希望这样的工作:
CREATE [OR REPLACE] PROCEDURE <name_of_procedure> [ (<ENTITY_KEY_variable>) ]
IS
<ENTITY_KEY=ENTITY_KEY_variable>
BEGIN
<your code goes here>
[EXCEPTION
exception_section]
END [procedure_name];
编辑:我从第一个发布的答案中看到我爱上了拖钓?傻我。
【讨论】:
@@Bryan Devaney:您的代码将永远无法在 Oracle 中运行。请修改。 不好意思,在sql下弹出,还以为是mysql。。。现在更新答案以上是关于不要重复自己:相同的 SQL 查询,但有两个不同的表的主要内容,如果未能解决你的问题,请参考以下文章
LINQ 和 SQL 中看似等效的查询返回不同的结果 [重复]