我有一个包含两列的表:col_order
(int)和name
(text)。我想检索有序行,这样当col_order
不为null时,它确定顺序,但是当它为null时,name
确定顺序。我想到了一个像
order by coalesce( col_order, name )
但是,这不起作用,因为两列具有不同的类型。我正在考虑将两者都转换为bytea,但是:1)转换整数是一种更好的方法,而不仅仅是将moding循环256,并在函数中堆叠单个字节,以及2)如何转换“name”以确保一些一种理智的整理顺序(假设名称有顺序......好citext会很好,但我没有费心去重建......目前UTF8)。
即使所有这一切都是可能的(欢迎细节的建议),似乎还有很多工作要做。还有更好的方法吗?
修改
戈登得到了一个很好的答案,但它表明我没有正确地说出这个问题。我希望按name
排序,其中col_order
表示此订单被覆盖的地方。这不是一个很好的问题,但这是一个可接受的解决方案:
col_order| name
----------------
null | a
1 | foo
null | foo1
2 | bar
即 - 如果col_order
为空名,则应在按名称最接近字母顺序后插入名称,但小于该名称。否则,可以通过以下方式获得:
order by col_order nulls last, name
编辑2
好的......为了让你的创意充满活力,这似乎正朝着正确的方向发展:
with x as ( select *,
case when col_order is null then null else row_number() over (order by col_order) end as ord
from temp )
select col_order, name, coalesce( ord, lag(ord,1) over (order by name) + .5) as ord from x;
当没有col_order
时,它会从上一行获取按名称排序的顺序。一般来说这是不对的...我想我必须回到非空col_order
的第一行......似乎sql标准对于窗口函数有“忽略空值”可能会这样做,但没有在postgres中实现。有什么建议吗?
编辑3
以下内容似乎很接近 - 但不起作用。对于递归查询,窗口评估可能有点奇怪。
with recursive x(col_order, name, n) as (
select col_order, name, case when col_order is null then null
else row_number() over (order by col_order) * t end from temp, tot
union all
select col_order, name,
case when row_number() over (order by name) = 1 then 0
else lag(n,1) over (order by name) + 1 end from x
where x.n is null ),
tot as ( select count(*) as t from temp )
select * from x;
答案 0 :(得分:3)
只需使用多个子句:
order by (case when col_order is not null then 1 else 2 end),
col_order,
name
当col_order
为not null
时,会为第一个排序键分配1
。如果是null
,则会分配2
。因此,not-nulls
将是第一个。
答案 1 :(得分:0)
好的..以下似乎有效 - 我将留下问题"未得到答复"虽然有待批评或更好的建议:
使用here中的last_agg聚合:
with
tot as ( select count(*) as t from temp ),
x as (
select col_order, name,
case when col_order is null then null
else (row_number() over (order by col_order)) * t end as n,
row_number() over (order by name) - 1 as i
from temp, tot )
select x.col_order, x.name, coalesce(x.n,last_agg(y.n order by y.i)+x.i, 0 ) as n
from x
left join x as y on y.name < x.name
group by x.col_order, x.n, x.name, x.i
order by n;