【问题标题】:How to Refer to a Column by ID or Index Number如何通过 ID 或索引号引用列
【发布时间】:2016-08-15 14:14:01
【问题描述】:

在 Oracle PL/SQL 中,我运行了一个查询并尝试逐一读取每一行的每一列,以便我可以将它们与分隔符连接在一起(硬格式要求)。该脚本用于多个不同大小的表,因此事先不知道列数。我用过

SELECT COUNT(column_name) INTO NumColumns FROM all_tabs_cols
WHERE table_name = Table_Array(i);

其中已经定义了 Table_Array。这是在 for 循环的中间,并且成功地让我获得了总列数。 Table_Cursor 是一个 SELECT * 语句。在此之后,我正在尝试做类似的事情

FOR j IN 0..NumColumns-1 LOOP
    FETCH TABLE_CURSOR.column(j) INTO DataValue;
    DBMS_OUTPUT.PUT(DataValue || '/');
END LOOP

以上是伪代码。它说明了我所追求的概念。我不太了解 PL/SQL,不知道如何从一行中获取这样的值。我也担心在执行此操作时意外推进光标。我怎样才能完成这项任务?

【问题讨论】:

  • 谁不只使用 LISTAGG 或其他一些聚合函数?
  • 这不是你应该使用 SQL 的方式——SQL 是基于设置的——一旦你看到你就有麻烦了。
  • @Hogan,我很害怕。那么有什么更好的方式来获取这些信息呢?
  • @OldProgrammer,LISTAGG 会很棒,因为我已经用它来获取标题信息。问题是它似乎只沿着列向下,而不是跨行。我有 1000 行 3 列,我需要 1/A1/B1/C1,然后是 2/A2/B2/C2 等。有没有办法让 LISTAGG 跨行工作?
  • @SandPiper - 最好的方法是编写一些代码来生成快速的代码并运行它。看我的回答——它只有一行。

标签: sql oracle


【解决方案1】:

您必须使用某种形式的动态 SQL。这是一个简单的例子:

它构建的 SQL 语句将从您想要的表中选择“/”分隔的列。然后它使用动态 SQL 来运行该 SQL 语句。

DECLARE
  p_table_name VARCHAR2(30) := 'DBA_OBJECTS';
  l_sql VARCHAR2(32000);

  TYPE varchar2tab IS TABLE OF VARCHAR2(32000);
  l_array varchar2tab;

BEGIN
  SELECT 'SELECT ' || listagg(column_name,' ||''/''||') within group ( order by column_id ) || ' FROM ' || owner || '.' || table_name || ' WHERE ROWNUM <= 100'
  INTO l_sql
  FROM dba_tab_columns
  where table_Name = 'DBA_OBJECTS'
  group by owner, table_Name;

  EXECUTE IMMEDIATE l_sql BULK COLLECT INTO l_array;

  FOR i in l_array.first .. l_array.last LOOP
    dbms_output.put_line(l_array(i));
  END LOOP;
END;

【讨论】:

  • 这就像一个冠军。我唯一改变的是在运行 EXECUTE IMMEDIATE 之前将整个 l_sql 作为一个字符串放在一起。非常感谢!
  • 不客气。确保添加适当的错误处理。 Oracle 行可以(很多!)超过 32,000 字节。此外,这不适用于具有某些数据类型的表(例如,LONG)。
  • 我还在学习 SQL。出于我的好奇心,为什么它不适用于 LONG 数据类型?还有什么?
  • LONG 不能隐式转换为 VARCHAR2。事实上,众所周知,它甚至不能显式转换为 VARCHAR2。与它们一起工作很痛苦,我 99% 确信,如果 Oracle 摆脱它们,每个人都会很高兴。其他类型?我不确定……任何不能隐式转换为 VARCHAR2 的东西。 LONG 总是让人想起。也许某些专门的 Oracle Spatial 数据类型可能会出现问题。所有常见的数据类型:NUMBERDATEVARCHAR2 都可以。但是(请参阅下一条评论...)
  • DATE 列将使用您的 NLS_DATE_FORMAT 设置进行隐式转换。使用TO_DATE(_columnName_,'DD-MON-YYYY') 或类似的东西来构建你的SQL 会是更好的做法。
【解决方案2】:

你的代码应该是这样的:

SELECT F1 || ', ' || F2 || ', ' || ... || ', ' || FN
FROM TABLE

没有循环


以下是生成不使用循环的代码的方法。 请注意,如果您愿意,可以取出 where 语句并为整个数据库生成代码。 先用一张表进行测试。

SELECT 'SELECT '|| LISTAGG(COLUMN_NAME, ' || '', '' || ') || ' FROM '||TABLE_NAME as sql_stm
FROM ALL_TAB_COLUMNS 
WHERE TABLE_NAME='tablename'
GROUP BY TABLE_NAME;

【讨论】:

  • 所以你的意思是说,如果他有 1000 张桌子,他每次都必须按照上述方式进行。我希望你明白我的意思。
  • 这没有帮助。我的问题与@Raj_Te 所说的完全一样。我有很多表,表结构偶尔会发生变化。我无法控制。我必须使用动态 SQL 脚本来获取它。我不知道表的列名是什么,所以我需要通过索引来引用它。
  • 完全 编写一些生成上述代码的sql。不要使用循环。循环很慢。
  • 次要:是LISTAGG(),而不是LIST_AGG()
猜你喜欢
  • 2014-07-06
  • 2019-11-27
  • 2018-04-05
  • 2019-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-30
  • 2011-11-22
相关资源
最近更新 更多