使用 SQL 或 PL/SQL 对多个表中的列和表名进行动态查询

Posted

技术标签:

【中文标题】使用 SQL 或 PL/SQL 对多个表中的列和表名进行动态查询【英文标题】:Dynamic query with columns and table names from multiple tables using SQL or PL/SQL 【发布时间】:2015-04-18 11:16:46 【问题描述】:

假设(为简单起见)我有两个表:

Product
 product_id
 CreatedDate
 LastEditedBy
 EditedDate

Entity
 entity_id
 CreatedDate
 LastEditedBy
 EditedDate

两个表具有相同的列名,但只有 ID 列具有不同的名称。我想运行一个查询,这样当我从 SQL plus 运行它时,我只需给它一个参数,它就会从其中一个表中获取数据。在上面的示例中,我可以像这样运行查询

@archiveHistory.sql product
@archiveHistory.sql entity

这是我的尝试,但它总是无法识别其中一列,即如果我使用产品运行它,它会说 entity_id 不存在。如果我用实体运行它,它说 product_id 不存在。

请注意,我在列选择和表名选择中都使用了传入的参数。

define identifier = '&1'

Select * from (
 Select case lower('&identifier')
  when product then product_id 
  when entity then entity_id
  end ID, CreatedDate, LastEditedBy, EditedDate
 From &identifier
)

如果 CASE 语句中的列列表都来自同一个表,我认为它会起作用。

问题

我需要做什么才能让查询忽略不相关的列,即如果参数是实体,则忽略 product_id

我考虑过使用匿名 PL/SQL 块(即 Begin End),但我不确定如何在不使用 dbms_output.put_line 的情况下显示输出。

【问题讨论】:

【参考方案1】:

对于这种特殊情况,我认为以下纯 SQL 解决方案可能效果最好:

SELECT product_id AS the_field
     , CreatedDate, LastEditedBy, EditedDate
FROM   Product
WHERE  LOWER('&identifier') = 'product'
UNION ALL
SELECT entity_id AS the_field
     , CreatedDate, LastEditedBy, EditedDate
FROM   Entity
WHERE  LOWER('&identifier') = 'entity'

查询计划器将预先评估您的 '&identifier' = ... 谓词,从而防止执行不需要的联合子查询。

如果这不是一个选项(因为您的实际用例要复杂得多),Stack Overflow 上已经有很多关于从 PL/SQL 执行动态 SQL 的答案:

Executing a dynamic sql statement into a SYS_REFCURSOR Cursor For Loop with dynamic SQL-Statement Binding Parameters to Oracle Dynamic SQL

您可以使用动态 SQL 将数据插入到临时表中,然后只需 SELECT * FROM temp_table

【讨论】:

OP 说我们应该假设他们有两个表“为简单起见”。我怀疑在现实生活中他们还有更多。 @APC:我同意,我从 "对于这个特殊情况" :-) 开始,但如果不存在该免责声明(“为简单起见” ),这将是一个更通用的问题的有用答案,人们在谷歌搜索此类主题时会找到该问题。因此,即使它可能对 OP 没有用,它也可能对其他人有用。

以上是关于使用 SQL 或 PL/SQL 对多个表中的列和表名进行动态查询的主要内容,如果未能解决你的问题,请参考以下文章

如何从sqlite中的计算列和表中的列计算天数

PL/SQL 使用一张表中的列数据更新表,基于不同表之间的相等性

Oracle PL / SQL触发器,在UPDATE之前/之后仅用于识别表中已修改的列

如何使用PL / SQL更改您在FOR循环IN子句中查询的表

如何创建验证另一个表中的列的 PL/SQL 行触发器

如何使用 PL/SQL 中的过程在表中插入多个值?