【问题标题】:SQL Dynamic ASC and DESCSQL 动态 ASC 和 DESC
【发布时间】:2014-11-19 11:22:40
【问题描述】:

我有以下 SQL 语句,其中 order by 子句是动态传递的。 如何将“按 asc 和 desc 排序”动态传递给 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

我想将order by asc or desc动态传递给上面的SQL,

我该怎么做?

【问题讨论】:

  • order by 没有意义。无论:odb 的值如何(1null 的值),它总是按常数值排序 - 因此它根本不是真正的“排序”。
  • @a_horse_with_no_name 我有多个案例陈述。所以不确定如何将 asc 或 desc 传递给 sql 或动态函数。
  • 如果列是数字的,你可以使用类似column_name * -1 的东西来进行降序排序,这可以变成动态的。但同样:您当前的示例不会对任何内容进行排序。
  • @a_horse_with_no_name 如果是这种情况如何动态传递order by参数和ascdesc
  • 只是为了消除混淆,@Polppan,当你写ORDER BY 1 时,1 的意思是“第一列”。但是当你写ORDER BY CASE WHEN ... THEN 1 END 时,1 不再意味着第一列,它只是文字值1,就像@a_horse_with_no_name 状态一样。当您在ORDER BY 中执行表达式时,您不能使用使用列号的快捷方式,但必须命名列(或列别名)。

标签: sql oracle sql-order-by


【解决方案1】:

您可以通过操作数字或数据值来解决 @TonyAndrews 之类的问题。对于VARCHAR2,动态 SQL 的替代方案可能是有两个表达式:

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

:sorting 的值为'ASC' 时,ORDER BY 的结果就像是:

order by
   col1 ASC,
   NULL DESC

:sorting 的值为'DESC' 时,ORDER BY 的结果就像是:

order by
   NULL ASC,
   col1 DESC

这种方法的一个缺点是优化器可以跳过 SORT 操作的情况,因为涉及的索引使数据已经按预期排序,而在使用这样的 CASE 方法时不会发生这种情况。无论如何,这将强制执行排序操作。

【讨论】:

  • 或者我需要为每一列写一个case语句?
  • @Polppan 您的绑定变量:col1 不能包含列名,这将不起作用。如果您执行ORDER BY :col1 并且:col1 的值是MYCOLUMN,那么就好像您编写了ORDER BY 'MYCOLUMN',它按常数值排序,而不是按列MYCOLUMN。然后,您需要为每列添加一个 case 语句,或者动态构建 SQL 语句——即将 SQL 构建为字符串并使用 IF/CASE 逻辑在 SQL 字符串中附加所需的顺序,然后再执行它。如何完成取决于您的环境 - PL/SQL、.NET、Java 或其他。
  • 感谢@KimBergHansen 的解决方案。
【解决方案2】:

如果您排序的列是数字,那么您可以这样做:

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

对于日期列,您可以这样做:

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

除了使用动态 SQL 来构造查询(当然适用于任何数据类型)之外,我想不出一种合理的方法来处理 VARCHAR2 列。

【讨论】:

    【解决方案3】:

    这适用于所有数据类型:

    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
    

    【讨论】:

    • Jeffrey,如果我有一个带连接的 SQL,我该怎么做?
    • 只需将它们放在table 的位置即可。
    • 我已经用我的加入 SQL 更新了我的问题(虽然它是示例)我如何修改我的 SQL 以纳入您的建议?谢谢
    • 只需根据您的 SQL 将 table 制作成子查询。
    【解决方案4】:

    不幸的是,您不能动态地执行此操作,因为 Oracle 基于这些 ASCDESC 关键字构建执行计划。 您可以做的是将 ORDER BY 子句更改为:

    SELECT * table 
     ORDER BY :order_param
    

    如果您想通过ASC 订购它,则将:odb 值传递给:order_param(更大的:odb 值将是最少的)或1/:odb 如果您想通过DESC 订购(更大:odb 值会产生较小的 1/:odb 值,并会出现在结果的顶部)。 而且,与往常一样,您可以在存储过程中动态生成查询:

    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;
    

    【讨论】:

    • 我觉得你回答的后半部分对我来说是明智的,更多的控制和前半部分我不太明白。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-14
    • 2018-09-21
    • 1970-01-01
    • 2014-07-11
    • 1970-01-01
    • 1970-01-01
    • 2012-04-25
    相关资源
    最近更新 更多