我最近遇到了一个Postgres SQL select测试问题,这个问题我没有看到,也很难找到正确的答案。一个表基本上包含一本书的页码和页面标题,并且对象是创建一个SELECT来对本书进行布局,如下所示:
左页,右页
其中left_page包含所有偶数页号,right_page包含所有奇数页号,但是其中0页显示空值,而任何非连续页都将具有空值。可以有空白页,因此页码可以跳过。
我的猜测是使用滞后或超前功能按顺序查找下一页,然后查看它是否连续,但是遇到问题。
这是一个例子:
create table mysharkbook (page_no integer not null, title varchar(30) not null, unique(page_no));
insert into mysharkbook (page_no,title) VALUES (1,'Hammerhead');
insert into mysharkbook (page_no,title) VALUES (2,'Great White');
insert into mysharkbook (page_no,title) VALUES (3,'Blue');
insert into mysharkbook (page_no,title) VALUES (4,'Tiger');
insert into mysharkbook (page_no,title) VALUES (6,'Blacktip');
select * from mysharkbook;
结果
1 "Hammerhead"
2 "Great White"
3 "Blue"
4 "Tiger"
6 "Blacktip"
现在,尝试使SELECT这样列出:
left_page, right_page
null | Hammerhead
Great White | Blue
Tiger | null
Blacktip | null
这是我(可怜的)尝试:
SELECT CASE WHEN prev_page IS NULL OR prev_page <> page_no - 1 OR (page_no % 2) = 0 THEN NULL ELSE title END As left_title,
CASE WHEN (page_no % 2) = 1 THEN title ELSE NULL END As right_title
FROM
(
SELECT LAG (page_no, 1) OVER (
ORDER BY
page_no
) AS prev_page,
title,page_no
from mysharkbook
order by page_no
) d
有什么最好的想法吗?
答案 0 :(得分:1)
完整的子查询联接可能会获得奇数页和偶数页。对于奇数页,我们还附加了generate_series()
来获取可能丢失的页面。
SELECT even.title left_page,
odd.title right_page
FROM (SELECT *
FROM mysharkbook b
WHERE b.page_no % 2 = 0) even
FULL JOIN (SELECT gs.pn page_no,
b.title
FROM generate_series(1,
(SELECT max(b.page_no)
FROM mysharkbook b),
2) gs (pn)
LEFT JOIN mysharkbook b
ON b.page_no = gs.pn) odd
ON odd.page_no = even.page_no + 1
ORDER BY odd.page_no;
(P.S .:我喜欢以鲨鱼为样本的想法!不是一次又一次地使用水果。)
答案 1 :(得分:1)
我相信这就是您想要的;
WITH cte
AS (
SELECT generate_series(0, (
SELECT max(page_no) max_pages
FROM mysharkbook
)) AS page
)
SELECT cte.page
,l.title l_title
,r.title r_title
FROM cte
LEFT OUTER JOIN mysharkbook l ON l.page_no = cte.page
LEFT OUTER JOIN mysharkbook r ON r.page_no = cte.page + 1
WHERE mod(page, 2) = 0
ORDER BY page
也许有更好的方法。
-HTH
答案 2 :(得分:1)
另一个:
select distinct on (page.no / 2)
msb.title, lead(msb.title) over(order by page.no)
from generate_series(0, (select max(page_no) from mysharkbook)) page(no)
left join mysharkbook msb on page.no = msb.page_no
order by page.no / 2
输出:
答案 3 :(得分:1)
另一种方法是将页面标题放入两个元素的数组中
select
page_titles[1] as left_page, page_titles[2] as right_page
from
(
select
page.no / 2 as even_pages, array_agg(title order by page.no) as page_titles
from generate_series(0, (select max(page_no) from mysharkbook)) page(no)
left join mysharkbook msb on page.no = msb.page_no
group by even_pages
) t
答案 4 :(得分:1)
单次加入和分组依据的另一种方法。
使用最小/最大无关紧要。该技术是使用模2取偶数和奇数页。如果我没记错的话,这模拟了Oracle的MIN + KEEP DENSE_RANK组合。
select
min(title) filter(where page.no % 2 = 0) as left_page,
min(title) filter(where page.no % 2 = 1) as right_page,
max(title) filter(where page.no % 2 = 0) as left_page_x,
max(title) filter(where page.no % 2 = 1) as right_page_x
from generate_series(0, (select max(page_no) from mysharkbook)) page(no)
left join mysharkbook msb on page.no = msb.page_no
group by page.no / 2
order by page.no / 2
说明:
答案 5 :(得分:0)
由于页码可以跳过,因此生成从0到max(page_no)的序列将产生完全空白的结果(左侧为null,右侧为null)。
如何将记录集分为偶数和奇数堆,并按顺序将2个记录集连接在一起->左页+ 1 =右页。
-- Test accepted solution by an additional row
insert into mysharkbook (page_no,title) VALUES (10,'Baby shark');
SELECT ls.title, rs.title
FROM
(SELECT * FROM mysharkbook WHERE mod(page_no,2) = 0) as ls
FULL OUTER JOIN
(SELECT * FROM mysharkbook WHERE mod(page_no,2) <> 0) as rs
ON ls.page_no + 1 = rs.page_no
ORDER BY COALESCE(ls.page_no, rs.page_no);
但这确实需要在同一张桌子上进行2次传球-也许不是那么出色。