从表列创建动态SQL选择

时间:2017-10-12 10:36:29

标签: sql oracle dynamic

我需要创建一个sql脚本,从表表中将以下列方式构建动态sql请求: 选择ID || ','||姓名|| ','||码 来自TABLE_TEST;

表名作为输入参数接收。

我的SQL脚本如下;

spool exportTable.log
SET HEAD OFF
SET TRIMOUT ON
SET TRIMSPOOL ON
SET LINESIZE 32000
SET PAGESIZE 0
SET TERMOUT OFF
SET ECHO OFF
SET COLSEP ,
procedure CreerReq(sTable in Varchar) is

dbms_output.put_line('dans CreerReq');
sqlreq VARCHAR2(2000);
sChaine VARCHAR2(4000):='select';
TYPE t_tab IS  TABLE OF VARCHAR2(4000);
l_tab t_tab;
l_tab_Id t_tab;
l_ref_cursor SYS_REFCURSOR;
dbms_output.put_line(sChaine);

begin
    sqlreq := 'select column_name from all_tab_cols WHERE  table_name' || sTable;
    dbms_output.put_line(sqlreq);
    OPEN l_ref_cursor FOR sqlreq;
    LOOP
     FETCH l_ref_cursor BULK COLLECT INTO l_tab_Id,l_tab limit 1000;
     EXIT WHEN l_tab.COUNT=0;
     FOR i IN l_tab.first .. l_tab.last LOOP
        sChaine:=l_tab(i) ' || ','';
     END LOOP;
     CLOSE l_ref_cursor;
     dbms_output.put_line(sChaine);
End CreerReq;

BEGIN


dbms_output.put_line('&1');
    CreerReq(&1);
END;
/
spool off;

但是这会给我带来以下错误:

  

ORA-00900:无效的SQL语句

请帮忙吗?

2 个答案:

答案 0 :(得分:0)

CREATE or replace FUNCTION build_select (
    p_owner        IN VARCHAR2
  , p_table_name   IN VARCHAR2
)
    RETURN VARCHAR2
AS
    l_ret   VARCHAR2 (32767);
BEGIN
    FOR eachcol IN (  SELECT column_name
                           , LEAD (column_name)
                                 OVER (
                                     PARTITION BY table_name ORDER BY column_id
                                 )
                                 next_column
                        FROM all_tab_cols
                       WHERE owner = p_owner
                         AND table_name = p_table_name
                    ORDER BY column_id)
    LOOP
        l_ret   := l_ret || eachcol.column_name || CASE WHEN eachcol.next_column IS NULL THEN NULL ELSE ',' END;
    END LOOP;

    IF l_ret IS NULL
    THEN
        raise_application_error (-20001, 'table ' || p_owner || '.' || p_table_name || ' not found');
    END IF;

    l_ret   := 'select ' || l_ret || ' from ' || p_owner || '.' || p_table_name;

    RETURN l_ret;
END build_select;

所以让我们测试一下:

begin dbms_output.put_line(build_select('SYS', 'ALL_TAB_COLS')); end;

结果:

select OWNER,TABLE_NAME,COLUMN_NAME,DATA_TYPE,DATA_TYPE_MOD,DATA_TYPE_OWNER,DATA_LENGTH,DATA_PRECISION,DATA_SCALE,NULLABLE,COLUMN_ID,DEFAULT_LENGTH,DATA_DEFAULT,NUM_DISTINCT,LOW_VALUE,HIGH_VALUE,DENSITY,NUM_NULLS,NUM_BUCKETS,LAST_ANALYZED,SAMPLE_SIZE,CHARACTER_SET_NAME,CHAR_COL_DECL_LENGTH,GLOBAL_STATS,USER_STATS,AVG_COL_LEN,CHAR_LENGTH,CHAR_USED,V80_FMT_IMAGE,DATA_UPGRADED,HIDDEN_COLUMN,VIRTUAL_COLUMN,SEGMENT_COLUMN_ID,INTERNAL_COLUMN_ID,HISTOGRAM,QUALIFIED_COL_NAME from SYS.ALL_TAB_COLS

这是一个更简单的build_select函数:

CREATE OR REPLACE FUNCTION build_select (
    p_owner        IN VARCHAR2
  , p_table_name   IN VARCHAR2
)
    RETURN VARCHAR2
AS
    l_ret   VARCHAR2 (32767);
BEGIN
    SELECT    
           LISTAGG (column_name, ',') WITHIN GROUP (ORDER BY column_id)
      INTO l_ret
      FROM all_tab_cols
     WHERE table_name = p_table_name
       AND owner = p_owner;

    IF l_ret IS NULL
    THEN
        raise_application_error (-20001, 'table ' || p_owner || '.' || p_table_name || ' not found');
    END IF;

    l_ret   := 'select ' || l_ret || ' from ' || p_owner || '.' || p_table_name;

    RETURN l_ret;
END build_select;

答案 1 :(得分:-1)

我有一段时间没有与oracle合作过。但是在sql server上,这是可以做到的。查看此代码,它可能会指向正确的方向:

/* This stored procedure builds dynamic SQL and executes 
using sp_executesql */
Create Procedure sp_EmployeeSelect
    /* Input Parameters */
    @EmployeeName NVarchar(100),
    @Department NVarchar(50),
    @Designation NVarchar(50),
    @StartDate DateTime,
    @EndDate DateTime,
    @Salary    Decimal(10,2)

AS
    Set NoCount ON
    /* Variable Declaration */
    Declare @SQLQuery AS NVarchar(4000)
    Declare @ParamDefinition AS NVarchar(2000) 
    /* Build the Transact-SQL String with the input parameters */ 
    Set @SQLQuery = 'Select * From tblEmployees where (1=1) ' 
    /* check for the condition and build the WHERE clause accordingly */
    If @EmployeeName Is Not Null 
         Set @SQLQuery = @SQLQuery + ' And (EmployeeName = @EmployeeName)'

    If @Department Is Not Null
         Set @SQLQuery = @SQLQuery + ' And (Department = @Department)' 

    If @Designation Is Not Null
         Set @SQLQuery = @SQLQuery + ' And (Designation = @Designation)'

    If @Salary Is Not Null
         Set @SQLQuery = @SQLQuery + ' And (Salary >= @Salary)'

    If (@StartDate Is Not Null) AND (@EndDate Is Not Null)
         Set @SQLQuery = @SQLQuery + ' And (JoiningDate 
         BETWEEN @StartDate AND @EndDate)'
    /* Specify Parameter Format for all input parameters included 
     in the stmt */
    Set @ParamDefinition =      ' @EmployeeName NVarchar(100),
                @Department NVarchar(50),
                @Designation NVarchar(50),
                @StartDate DateTime,
                @EndDate DateTime,
                @Salary    Decimal(10,2)'
    /* Execute the Transact-SQL String with all parameter value's 
       Using sp_executesql Command */
    Execute sp_Executesql     @SQLQuery, 
                @ParamDefinition, 
                @EmployeeName, 
                @Department, 
                @Designation, 
                @StartDate, 
                @EndDate,
                @Salary

    If @@ERROR <> 0 GoTo ErrorHandler
    Set NoCount OFF
    Return(0)

ErrorHandler:
    Return(@@ERROR)
GO