Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does a CASE statement lose alias scope in PostgreSQL?

First of all, this SQL works:

select
    case
        when s.luserid > 0 then u.szusername
        when s.lgroupid > 0 then g.szgroup
        when s.lldapid > 0 then 'LDAP Group'
    end as name
from security s
left join users u on s.luserid = u.id
left join usergroups g on s.lgroupid = g.id
order by name

The above block is proving ordering by alias name works, as well as declaring alias name works while the term name is a reserved word, which is not relevant to the question

My issue happens when I make a case statement with an alias in it:

Pay attention to the alias useid

select
    case
        when sa.luserid > 0 then sa.luserid
        when sa.lgroupid > 0 then sa.lgroupid
        when sa.lldapid > 0 then sa.lldapid
    end as useid,
from security s
left join users u on s.luserid = u.id
left join usergroups g on s.lgroupid = g.id
order by
        case
            when 'user selection' = 'all objects by user' then useid
            else s.lobjectid
        end

The text user selection is replaced by a parser with literal text before the SQL is run. Both the alias useid and s.lobjectid are type bigint.

An error is thrown at when 'user selection' = 'all objects by user' then useid.

Am I losing scope of the alias useid within the CASE statement? Why does this fail when I try to use the alias useid here.

By the way, this SQL works as well:

select
    case
        when s.luserid > 0 then u.szusername
        when s.lgroupid > 0 then g.szgroup
        when s.lldapid > 0 then 'LDAP Group'
    end as name
from security s
left join users u on s.luserid = u.id
left join usergroups g on s.lgroupid = g.id
order by
        case
            when s.lobjectid > 0 then s.lobjectid
            else s.luserid
        end

The above block is proving that a CASE statement within an ORDER BY statement does work. All debates over the logical operations of the above block of SQL is irrelevant to the question, for it is simply junk example SQL.

like image 456
WebWanderer Avatar asked Feb 25 '15 18:02

WebWanderer


People also ask

Can we give alias in case statement?

You can give an alias to a CASE expression exactly the same way as you give an alias to any other expression. After the complete expression, put the optional keyword AS (if you want to) and then the alias.

How does CASE statement work in PostgreSQL?

Introduction to PostgreSQL CASEEach condition is a boolean expression and based on its output the result is chosen. If all the expressions corresponding to WHEN are evaluated to be False , then the result respective to the ELSE part is shown. In case, you don't specify the ELSE part; the query will return null.

Is case statement supported in PostgreSQL?

The PostgreSQL CASE expression is the same as IF/ELSE statement in other programming languages. It allows you to add if-else logic to the query to form a powerful query. Since CASE is an expression, you can use it in any places where an expression can be used e.g., SELECT , WHERE , GROUP BY , and HAVING clause.

What does an alias do in PostgreSQL?

In PostgreSQL, an alias is a temporary alternative name for columns, tables, views, materialized views, etc. in a query. Aliases are assigned during query execution and aren't stored in the database or on disk. By using column aliases, the query output can become more meaningful.


1 Answers

What you are trying to do is not possible in Postgresql since it doesn't allow you to use an ALIAS within the same query as a field. Different from Mysql where you can do it.

To solve your problem you either create your query as a subquery and then your alias will be a field therefore can be used as:

select useid, lobjectid from (
  select
      case
          when sa.luserid > 0 then sa.luserid
          when sa.lgroupid > 0 then sa.lgroupid
          when sa.lldapid > 0 then sa.lldapid
      end as useid,
      lobjectid
   from security s
  left join users u on s.luserid = u.id
  left join usergroups g on s.lgroupid = g.id
  ) as t
order by
        case
            when 'user selection' = 'all objects by user' then useid
            else lobjectid
        end

Or you can repeat the entiry case block

  select
      case
          when sa.luserid > 0 then sa.luserid
          when sa.lgroupid > 0 then sa.lgroupid
          when sa.lldapid > 0 then sa.lldapid
      end as useid,
      lobjectid
   from security s
  left join users u on s.luserid = u.id
  left join usergroups g on s.lgroupid = g.id
order by
        case
            when 'user selection' = 'all objects by user' then 
                  case
                      when sa.luserid > 0 then sa.luserid
                      when sa.lgroupid > 0 then sa.lgroupid
                      when sa.lldapid > 0 then sa.lldapid
                  end
            else lobjectid
        end

Some engines will let you use the order number of the field on the select scope to the order by like:

select a, b, c from sometable order by 1, 2

Which means that this query will be ordered by the fields a and b

like image 150
Jorge Campos Avatar answered Oct 08 '22 10:10

Jorge Campos