是否可以将列作为参数传递给 ORDER BY 子句?

Posted

技术标签:

【中文标题】是否可以将列作为参数传递给 ORDER BY 子句?【英文标题】:Is it possible to pass a column as a parameter to a ODER BY clause? 【发布时间】:2018-01-09 12:03:08 【问题描述】:

我想在 Oracle 中使用一个函数。但我需要根据用户作为参数传递的内容进行相应的 ORDER BY。

例子:

FUNCTION foo_function(p_date IN DATE, p_column_number IN NUMBER)
RETURN foo_bar
IS
BEGIN
   SELECT * FROM bar WHERE date = p_date ORDER BY p_column_number
   <...other code...>
END;

此块不起作用。 是否可以这样做将列作为参数传递给 ORDER BY 子句?

更新 ----------

@XING 展示了一种非常好的解决问题的方法,无需 DECODE,就像其他问题的答案一样。

但问题是我遗漏了一些东西。 现在我收到此错误:"inconsistent datatypes: expected %s got %s"

-- Creating my object with 2 columns.
CREATE OR REPLACE TYPE MY_OBJECT AS OBJECT(IDOP NUMBER, EMISSION_DATE DATE);

-- Creating the table of MY_OBJECT type.
CREATE OR REPLACE TYPE TB_OBJECT AS TABLE OF MY_OBJECT;

-- Creating my function
CREATE OR REPLACE FUNCTION GET_OBJECT(
   P_INITIAL_DATE IN DATE,
   P_FINAL_DATE IN DATE,
   P_COLUMN_NUMBER   IN   NUMBER)
   RETURN TB_OBJECT
IS
   V_TB       TB_OBJECT;
   V_SQL      VARCHAR2(1000);
BEGIN
   V_SQL :=
      'SELECT IDOP, EMISSION_DATE FROM OP WHERE EMISSION_DATE BETWEEN :p_initial_date AND :p_final_date ORDER BY :p_column_number';

   EXECUTE IMMEDIATE V_SQL
   BULK COLLECT INTO V_TB
             USING P_COLUMN_NUMBER;

   RETURN (V_TB);
END;

-- Calling the function
SELECT * FROM TABLE (GET_OBJECT(TO_DATE('01/06/2017','dd/MM/yyyy'), TO_DATE('09/01/2018', 'dd/MM/yyyy'), 1));

更新(2)---------

我的代码中的问题是我忘记将选择强制转换为我的对象。

这样代码就可以工作了。

V_SQL :=
      'SELECT MY_OBJECT(IDOP, EMISSION_DATE) FROM OP WHERE EMISSION_DATE BETWEEN :p_initial_date AND :p_final_date ORDER BY :p_column_number';

谢谢@XING

【问题讨论】:

How to generate Dynamic Order by clause in PL/SQL procedure?的可能重复 您好,需要研究动态SQLdocs.oracle.com/cloud/latest/db112/LNPLS/dynamic.htm#LNPLS011 【参考方案1】:

在下面的示例中,我向您展示了如何通过仅订购 1 列来在函数中执行此操作。您可以根据需要修改功能;

--Created a type of number to return the ordered result. You can create an object with the column same as used in your select statement.
CREATE OR REPLACE TYPE VAR_RET AS TABLE OF NUMBER;
/

--功能

CREATE OR REPLACE FUNCTION FOO_FUNCTION (     
     P_COLUMN_NUMBER   IN   NUMBER)
     RETURN VAR_RET
IS
     V_RES                         VAR_RET;
     v_sql                         VARCHAR2(1000);
BEGIN
     V_SQL :=
          'SELECT EMPNO FROM EMP   ORDER BY :p_column_number'; --<-- Create Object with all the columns you are selecting here and then a type of your object to hold result

     EXECUTE IMMEDIATE V_SQL
     BULK COLLECT INTO V_RES
                 USING P_COLUMN_NUMBER;

     RETURN (V_RES);
END;

--结果:

SQL>  select * from table( FOO_FUNCTION (1));

COLUMN_VALUE
------------
        7369
        7499
        7521
        7566
        7654
        7698
        7782
        7788
        7839
        7844
        7876

编辑:使用 2 列排序

CREATE OR REPLACE TYPE MY_TAB AS OBJECT
(
 V_EMPNM   VARCHAR2(100),
 V_EMPNO   NUMBER
);

CREATE OR REPLACE  TYPE VAR_RET AS TABLE OF MY_TAB;
/



CREATE OR REPLACE FUNCTION FOO_FUNCTION (     
     P_COLUMN_NUMBER   IN   NUMBER)
     RETURN VAR_RET
IS
     V_RES                         VAR_RET;
     v_sql                         VARCHAR2(1000);
BEGIN
     V_SQL := --You need to cast your select statement as per Object
          'SELECT MY_TAB(ENAME,EMPNO) FROM EMP ORDER BY :p_column_number'; --<-- Create Object with all the columns you are selecting here and then a type of your object to hold result

     EXECUTE IMMEDIATE V_SQL
     BULK COLLECT INTO V_RES
                 USING P_COLUMN_NUMBER;

     RETURN (V_RES);
END;

执行: 1)方式1

DECLARE
     VAR                           VAR_RET := VAR_RET ();
BEGIN
     VAR := FOO_FUNCTION (1);

     FOR I IN 1 .. VAR.COUNT
     LOOP
          DBMS_OUTPUT.PUT_LINE (VAR (I).V_EMPNM ||'  ' ||VAR (I).V_EMPNO);
     END LOOP;
END;

SQL> /
SMITH  7369
ALLEN  7499
WARD  7521
JONES  7566
MARTIN  7654
BLAKE  7698
CLARK  7782
SCOTT  7788
KING  7839
TURNER  7844
ADAMS  7876
JAMES  7900
FORD  7902
MILLER  7934

PL/SQL procedure successfully completed.

2) 方式 2

 select * from table( FOO_FUNCTION (1));

V_EMPNM                                                                                                 V_EMPNO
----------------------------------------------------------------------------------------------------
SMITH                                                                                                      7369
ALLEN                                                                                                      7499
WARD                                                                                                       7521
JONES                                                                                                      7566
MARTIN                                                                                                     7654
BLAKE                                                                                                      7698
CLARK                                                                                                      7782
SCOTT                                                                                                      7788
KING                                                                                                       7839
TURNER                                                                                                     7844
ADAMS                                                                                                      7876

V_EMPNM                                                                                                 V_EMPNO
----------------------------------------------------------------------------------------------------
JAMES                                                                                                      7900
FORD                                                                                                       7902
MILLER                                                                                                     7934

14 rows selected.

【讨论】:

感谢@XING,您的回答像魅力一样解决了我的问题。 如果我想要一个对象的表,我只需要先创建 MY_OBJECT,然后将表的类型(在您的示例中为 VAR_RET)设置为 MY_OBJECT。对吗? @Odilon 完全正确,但您根本无法声明对象变量。创建对象后,您将创建对象的类型。就像我在我的示例中创建了一种表格编号一样。试试看,如果您遇到任何问题,请告诉我 我更新了@XING 的问题。我遗漏了一些东西,因为我的函数不能处理多个列。 非常感谢!它工作得很好。我忘记将选择强制转换为我的对象。

以上是关于是否可以将列作为参数传递给 ORDER BY 子句?的主要内容,如果未能解决你的问题,请参考以下文章

在 Visual Studio 2008 中使用设计器将逗号分隔列表作为参数传递给 db2 查询的 IN 子句

是否可以将可变数量的参数传递给redshift中的存储过程?

将对象作为参数传递给 router.push (vue-router@4.05)

Rails“参数传递给#in?必须回复#include?“

您可以将 (2) 参数传递给 UNPIVOT 的 FOR 子句吗? - 甲骨文SQL

JPQL查询where子句使用IN,如何将参数传递给查询