根据布尔列升序或降序排列

4
这是PostgreSQL 10中的表结构。
enter image description here 虽然“date”是一个int类型,但它代表的是yyyy mm dd格式的日期。我想编写一个SELECT语句按日期排序,当BC=true时为desc,这样日期就会按正确顺序排列-500 01 02,然后是-500 01 03(yyyy mm dd)
当BC=false时为asc,这样日期就会再次按正确顺序排列1500 01 02,然后是150 01 03(yyyy mm dd)
我想到了这个SELECT * FROM test ORDER BY bc=true desc, bc=false asc;,它可以很好地处理BC日期,但是AD日期会反转(15000103然后是15000102,这是错误的)。
我知道有date类型可用,但我希望这可以作为精确BC日期的hack方法运行。
如何更改我的SELECT以根据BC布尔列正确排序日期?
谢谢
4个回答

7

我认为bc=true desc, bc=false asc并不起作用,待我拿到电脑后会再次检查并在稍后更新答案。

也许我的解决方案只是一个技巧或欺骗。这不是一种合法的方式。您可以尝试此方法。

SELECT * FROM test 
ORDER BY bc DESC, CASE WHEN bc THEN date*(-1) ELSE date END ASC;

或者
SELECT * FROM test 
ORDER BY bc DESC, CASE WHEN bc THEN abs(date) ELSE date END ASC;

希望我的答案能够满足您的需求。


简洁的解决方案,尤其是考虑到响应时间。 - Vao Tsun
你是在将整个日期列乘以-1吗?我正在尝试类似于伪代码的东西:SELECT * FROM test ORDER BY date IF bc=true THEN desc ELSE asc;但无论我尝试什么,都会出现语法错误。 - codebot
顺便说一句,它是有效的,但我认为用-1乘以所有东西很奇怪。如果我有20000行会怎么样?我只是试图根据顺序纯粹地语法化某些东西。但我一直得到错误。我尝试了嵌套选择、联合...什么都不起作用。这让我感到沮丧。 - codebot
如果您愿意,可以检查我的答案。与我的解决方案不同的是,我没有使用*(-1)。我不是专家,无法判断任何解决方案是更好还是更差,但我建议另一种解决方案。谢谢。 - codebot
非常抱歉,我昨天起就离开了电脑。对于你的问题,不是所有数据都要乘以(-1),只有bc = true的数据需要这样做,我已经将其放在CASE WHEN阶段中。或者你可以像@VaoTsun在下面的回答中建议的那样,用abs(date)替换date*(-1)。根据我的经验,PostgreSQL没有在“排序”中使用条件,你必须先预处理数据,然后按照你想要的ASC或DESC进行排序。 - Mabu Kloesen

0

我会选择绝对值

t=# with c(d) as (values(-51),(50))
select * from c order by abs(d);
  d
-----
  50
 -51
(2 rows)

啊,非常聪明的解决方案,但是,假设我有-50001025000102并执行SELECT * FROM test ORDER BY abs(date), bc desc;,我会得到-5000102 5000102 -5000103 5000103,所以还是不行。如果表格具有这些确切的固定值,那么可以,但是表格可以有任何值。 - codebot
@codebot:我认为他想展示另一种与我上面的答案相结合的方式。从而查询将是: SELECT * FROM test ORDER BY bc DESC, CASE WHEN bc THEN abs(date) ELSE date END ASC; - Mabu Kloesen

0

我相信一个简单的联合也可以解决它。

我在Fiddle上进行了测试: http://sqlfiddle.com/#!9/96ed2/1/0

看起来它是有效的:

( SELECT * FROM mytable 
WHERE bc=true 
ORDER BY date DESC) 

UNION ALL 
( SELECT * FROM mytable WHERE bc=false ORDER BY date)
ORDER BY bc DESC, date

我使用的数据集:

CREATE TABLE mytable (
  id serial PRIMARY KEY,  
  name VARCHAR (50),
  date INTEGER,
  bc BOOLEAN
);

INSERT INTO mytable (id, name, date, bc) VALUES (1,'one',-6000102, true);
INSERT INTO mytable (id, name, date, bc) VALUES (2,'two',-3000202, true);
INSERT INTO mytable (id, name, date, bc) VALUES (3,'three',-5000103, true);
INSERT INTO mytable (id, name, date, bc) VALUES (4,'four',19000109, false);
INSERT INTO mytable (id, name, date, bc) VALUES (5,'five',15000105, false);

你应该知道在编程中使用 UNION ALL 还是 UNION 更好。 (https://www.postgresql.org/docs/8.3/static/queries-union.html)

谢谢你的回答。问题在于,如果你添加另一个日期,比如“-5000102”,它们将无法正确排序。此外,联合查询不能保证两个结果的正确顺序,其他问题中的评论是正确的。因此,如果你愿意,请检查我的答案,我想出了另一种解决方案。 - codebot

0

在尝试了不同的语法组合后,我基于this得出了这个结果。

select * from test
 order by
 case when bc = true then bc end asc ,
 case when bc = true then date end desc,
 case when bc = false then date end asc,
 case when bc = false then bc end desc;

成功输出

-5000102
-5000103
-5000103
5000102
5000103
5000301
5000302
15000102
15000103

所以,日期格式为yyyy-mm-dd,从公元前到公元后,从旧到新。


是的,它可以工作。但我有一些担心,因为在这种情况下,它将检查4个条件,然后进行4次排序。如果数据很大,我认为这不会很好。顺便说一下,你可以试试。 此外,我们可以更多地讨论这个案例,使用Case阶段,如果您没有定义else阶段,它将是null,并且默认的ASCnulls last,反之亦然DESC。 您可以在此处查看有关“查询顺序”的更多信息https://www.postgresql.org/docs/10/static/queries-order.html - Mabu Kloesen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接