CASE 语句是否会在 PostgreSQL 中丢失别名作用域?

Does a CASE statement lose alias scope in PostgreSQL?

首先,这个 SQL 有效:

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

上面的块证明了按别名 name 排序是有效的,并且声明别名 name 是有效的,而术语 name 是一个保留字,它与问题无关

当我创建一个带有别名的 case 语句时,我的问题发生了:

注意别名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

在 SQL 为 运行 之前,文本 user selection 被解析器替换为文字文本。别名 useids.lobjectid 的类型都是 bigint.

when 'user selection' = 'all objects by user' then useid 处抛出错误。

我是否在 CASE 语句中丢失了别名 useid 的范围? 为什么当我尝试在此处使用别名 useid 时会失败。

顺便说一下,这个 SQL 也可以:

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

上面的块证明 ORDER BY 语句中的 CASE 语句确实有效。所有关于上述SQL块的逻辑运算的争论都与问题无关,因为它只是垃圾示例SQL。

您尝试执行的操作在 Postgresql 中是不可能的,因为它不允许您在与字段相同的查询中使用 ALIAS。不同于Mysql哪里可以做到。

要解决您的问题,您可以将查询创建为子查询,然后您的别名将是一个字段,因此可以用作:

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

或者您可以重复整个案例块

  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

有些引擎会让您使用 select 范围内字段的顺序号来排序,例如:

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

这意味着此查询将按字段 ab

排序