简体   繁体   中英

SQL Dynamic ASC and DESC

I have the following SQL statement where order by clause is passed dynamically . How can I pass 'order by asc and desc' dynamically to SQL?

SELECT table1.prod_id,table2.prod_name from table1 left outer join table2
              ON table1.prod1 = table2.prod_id 
              ORDER BY CASE WHEN :odb = 1 THEN prod_id END

I would like pass order by asc or desc to above SQL dynamically,

how can I do this?

You can do solutions like @TonyAndrews by manipulating numeric or data values. For VARCHAR2 an alternative to dynamic SQL could be to have two expressions:

order by
   case when :sorting='ASC' then col1 end ASC,
   case when :sorting='DESC' then col1 end DESC

When :sorting has the value 'ASC' the result of that ORDER BY becomes like if it had been:

order by
   col1 ASC,
   NULL DESC

When :sorting has the value 'DESC' the result of that ORDER BY becomes like if it had been:

order by
   NULL ASC,
   col1 DESC

One downside to this method is that those cases where the optimizer can skip a SORT operation because there is an index involved that makes the data already sorted like desired, that will not happen when using the CASE method like this. This will mandate a sorting operation no matter what.

If the column you are sorting by is numeric then you could do this:

order by case when :dir='ASC' then numcol ELSE -numcol END

For a date column you could do:

order by case when :dir='ASC' then (datecol - date '1901-01-01') 
              else (date '4000-12-31' - datecol) end

I can't think of a sensible way for a VARCHAR2 column, other than using dynamic SQL to construct the query (which would work for any data type of course).

Unfortunatelly, you can not do it dynamically, because Oracle builds the execution plan based on these ASC and DESC keywords. What you can do is changing the ORDER BY clause to this:

SELECT * table 
 ORDER BY :order_param

And pass :odb value to :order_param if you want to order it by ASC (bigger :odb values would be least in order) or 1/:odb if you want to order by DESC (bigger :odb values would produce smaller 1/:odb values and would appear on top of the result). And, as always, you can generate the query dynamically in a stored procedure:

IF ... THEN
  EXECUTE IMMEDIATE 'SELECT * table ORDER BY CASE WHEN :odb = 1 THEN 1 END ASC';
ELSE 
  EXECUTE IMMEDIATE 'SELECT * table ORDER BY CASE WHEN :odb = 1 THEN 1 END DESC';
END IF;

This will work for all data types:

SELECT *
FROM   (SELECT table.*
              ,ROW_NUMBER() OVER (ORDER BY prod_id) sort_asc
              ,ROW_NUMBER() OVER (ORDER BY prod_id DESC) sort_desc
        FROM   table)
ORDER BY CASE WHEN :odb = 1 THEN sort_asc ELSE sort_desc END

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM