条件子句

时间:2018-06-19 16:52:09

标签: oracle join sql-order-by union

以下查询返回错误。帮助我根据错误以及实现条件排序的方式。我试图按年级和名称排序(当年级> = 8时排序),并按等级和分数(当年级<8)时评分。

SELECT
    name, grade, marks
FROM
    students, grades
WHERE
    min_mark <= marks
    AND   marks <= max_mark
    AND   marks >= 70
UNION
SELECT
    TO_CHAR('NULL') AS name, grade, marks
FROM
    students, grades
WHERE
    min_mark <= marks
    AND   marks <= max_mark
    AND   marks <= 69
order by grade desc,(case when grade >= 8 
                     then  name 
                     when grade < 8 
                     then marks  
                     end );
  

错误:
  按等级desc排序(等级> = 8
的情况   *
  第18行出现错误:
  ORA-01785:ORDER BY项目必须是SELECT列表表达式的编号

2 个答案:

答案 0 :(得分:1)

这似乎是错误5695629,它似乎是针对10g提出的,并且似乎尚未修复(截至12cR2;我还没有18可以玩),这是不寻常的。 / p>

可以通过在订购前将查询包装在外部选择中来避免这种情况:

select name, grade, marks
from
(
    SELECT
        name, grade, marks
    FROM
        students, grades
    WHERE
        min_mark <= marks
        AND   marks <= max_mark
        AND   marks >= 70
    UNION
    SELECT
        TO_CHAR('NULL') AS name, grade, marks
    FROM
        students, grades
    WHERE
        min_mark <= marks
        AND   marks <= max_mark
        AND   marks <= 69
)
order by grade desc,case when grade >= 1 
                     then  name 
                     when grade < 1 
                     then  marks
                     end ;

但是由于namemarks是(大概)不同的数据类型-字符串和数字-而是会得到

  

ORA-00932:数据类型不一致:预期的CHAR得到了NUMBER

您可以将marks转换为字符串,但是如果这样做,则需要对其进行填充,以便按字母顺序对结果字符串进行排序仍与数字顺序匹配-混乱但合理,因为标记可以(再次,大概-这是一个百分比?)最多只能是三位数:

select name, grade, marks
from
(
    ...
    <the main part of your query here as a subquery, as above>
    ...
)
order by grade desc,case when grade >= 8 
                     then  name 
                     when grade < 8 
                     then  to_char(marks, 'FM000')
                     end ;

db<>fiddle demo使用通过CTE提供的一些虚拟数据。

如果标记可以超过三位数,则更改格式掩码以匹配最大可能长度。


TO_CHAR('NULL')部分也很奇怪,因为它将在名称列中为这些行提供文字字符串“ NULL”。由于您以字符串文字开头,TO_CHAR()部分毫无意义,因此直接使用'NULL' AS name。如果实际上希望它为空,则可以使用null AS name,它将与联合的第一个分支中的匹配列表达式的数据类型相匹配(并且也将选择其别名)。您可以显式转换为字符串类型,例如cast(null as varchar2(20)) AS name,但似乎没有多大意义。

答案 1 :(得分:0)

SQL中CASE Expressions有2种形式。

CASE <expression> WHEN <v1> THEN <ret1> WHEN <v2> THEN <ret2> ... END

另一个是

CASE WHEN <comp1> THEN <ret1> WHEN <comp2> THEN <ret2> ... END

区别在于,在情况1中,您指定了要比较一次的值或表达式,然后将其与其他值或表达式进行比较,与变量2一样,您为每个WHEN指定了一个比较表达式。

将表达式更改为

CASE WHEN grade >= 8 THEN name ELSE TO_CHAR(marks, '0999999999') END

我还将标记数字格式化为带有前导零的字符串,以使其可以与名称一起作为文本进行排序。