Postgresql 需要一些关于SQL的提示/建议(包括命令和一些优化)
我一直在寻找一种方法,从PostgreSQL中的Postgresql 需要一些关于SQL的提示/建议(包括命令和一些优化),postgresql,Postgresql,我一直在寻找一种方法,从PostgreSQL中的GROUP BY中选择第一项,直到我发现这个stackoverflow: 在那里,我看到使用了WITH命令。 我试图理解SQL的一些更“高级”的命令,如分区,带,行号等。直到两三个月前,我只知道基本的命令(选择,内部联接,左联接,按顺序,按顺序分组等) 我有一个小问题(已解决,但我不知道这是否是更好的方法) *better way=我更关心的是干净的SQL代码,而不是性能-这只适用于每天执行一次且不超过5000条记录的报表 在PostgreSQL中
GROUP BY
中选择第一项,直到我发现这个stackoverflow:
在那里,我看到使用了WITH
命令。
我试图理解SQL的一些更“高级”的命令,如分区,带,行号等。直到两三个月前,我只知道基本的命令(选择,内部联接,左联接,按顺序
,按顺序
分组等)
我有一个小问题(已解决,但我不知道这是否是更好的方法)
*better way=我更关心的是干净的SQL代码,而不是性能-这只适用于每天执行一次且不超过5000条记录的报表
在PostgreSQL中,我有两个表:
+----------------------------------------------+
| TABLE NAME: point |
+--------+---------------+----------+----------+
| km | globalid | lat | long |
+--------+---------------+----------+----------+
| 36600 | 1553E2AB-B2F8 | -1774.44 | -5423.58 |
| 364000 | 25EB2465-1B8A | -1773.42 | -5422.03 |
| 362000 | 5FFDE611-88DF | -1771.80 | -5420.37 |
+--------+---------------+----------+----------+
+---------------------------------------------------------+
| TABLE NAME: photo |
+--------------+---------------+------------+-------------+
| attachmentid | rel_globalid | date | filename |
+--------------+---------------+------------+-------------+
| 1 | 1553E2AB-B2F8 | 2015-02-24 | photo01.jpg |
| 2 | 1553E2AB-B2F8 | 2015-02-24 | photo02.jpg |
| 405 | 25EB2465-1B8A | 2015-02-12 | photo03.jpg |
| 406 | 25EB2465-1B8A | 2015-02-12 | photo04.jpg |
| 407 | 25EB2465-1B8A | 2015-02-13 | photo06.jpg |
| 3 | 5FFDE611-88DF | 2015-02-12 | photo07.jpg |
+--------------+---------------+------------+-------------+
因此,对于问题:
每个点
都有一张或多张照片,但我只需要点
数据,以及第一张和最后一张照片
。如果点
只有一张照片
,我只需要第一张照片
。如果点
有三张照片
,我只需要第一张和第三张照片
因此,我决定:
首先,我需要每个点的第一张照片
,因此,我按rel\u globalid
分组,并按组对每张照片编号:
WITH photos_numbered AS (
SELECT
rel_globalid,
date,
filename,
ROW_NUMBER()
OVER (
PARTITION BY rel_globalid
ORDER BY date
) AS photo_num
FROM
photo
)
有了这段代码,我也可以得到第二、第三等
好的,现在,我想得到第一张照片(仍然使用上面的和
):
为了获得最后一张照片,我使用了以下SQL:
SELECT
p1.*
FROM
photos_numbered p1
JOIN (
SELECT
rel_globalid,
max(photo_num) photo_num
FROM
photos_numbered
GROUP BY
rel_globalid
) p2
ON
p1.rel_globalid = p2.rel_globalid AND
p1.photo_num = p2.photo_num
WHERE
p1.photo_num > 1
其中p1.photo_num>1
是因为如果点
只有一张照片
,则该照片
将显示为第一张照片,最后一张照片将为空
好的,现在我必须将第一张照片的选择和最后一张照片的转换为带有的,并对第一张照片的内部连接和最后一张照片的左连接执行一个简单的选择:
WITH photos_numbered AS (
SELECT
rel_globalid,
date,
filename,
ROW_NUMBER()
OVER (
PARTITION BY rel_globalid
ORDER BY date
) AS photo_num
FROM
photo
), first_photo AS (
SELECT *
FROM
photos_numbered
WHERE
photo_num = 1
), last_photo AS (
SELECT p1.*
FROM
photos_numbered p1
JOIN (
SELECT
rel_globalid,
max(photo_num) photo_num
FROM
photos_numbered
GROUP BY
rel_globalid
) p2
ON p1.rel_globalid = p2.rel_globalid AND
p1.photo_num = p2.photo_num
WHERE
p1.photo_num > 1
)
SELECT DISTINCT
point.km,
point.globalid,
point.lat,
point."long",
first_photo.date AS fp_date,
first_photo.filename AS fp_filename,
last_photo.date AS lp_date,
last_photo.filename AS lp_filename
FROM
point
INNER JOIN
first_photo
ON
first_photo.rel_globalid = point.globalid
LEFT JOIN
last_photo
ON
last_photo.rel_globalid = point.globalid
ORDER BY
km
我认为这个SQL对于一件“简单的事情”来说是巨大的
他在工作吗?是的,但是我想要一些建议,一些我可以更好地阅读和理解的文档,一些我可以用来制作“更好”SQL的命令(就像我说的,大约两三个月前我甚至不知道分区和与命令)
我试图在这里为SQLFiddle添加一个链接,但SQLFiddle从未对我起作用(始终返回“oops”消息)。如果您正在寻找干净的SQL,请尝试使用第一个\u值和最后一个\u值窗口函数进行横向左连接,而不是使用公共表表达式(with子句):
当只有一条记录时,可以使用带有大小写表达式的附加count(*)over()
来“清除”最后一张照片的值:
select *
from point po
left join lateral
(
select first_value( date ) over( order by ph.date) as first_photo_date,
first_value( filename ) over( order by ph.date) as first_photo_filename,
case when count(*) over () > 1
then last_value( date ) over( order by ph.date)
end as last_photo_date,
case when count(*) over () > 1
then last_value( filename ) over( order by ph.date)
end as last_photo_filename
from photo ph
where po.globalid = ph.rel_globalid
limit 1
) q on true
;
如果要查找干净的SQL,请尝试使用第一个\u值和最后一个\u值窗口函数进行横向左联接,而不是使用公共表表达式(with子句):
当只有一条记录时,可以使用带有大小写表达式的附加count(*)over()
来“清除”最后一张照片的值:
select *
from point po
left join lateral
(
select first_value( date ) over( order by ph.date) as first_photo_date,
first_value( filename ) over( order by ph.date) as first_photo_filename,
case when count(*) over () > 1
then last_value( date ) over( order by ph.date)
end as last_photo_date,
case when count(*) over () > 1
then last_value( filename ) over( order by ph.date)
end as last_photo_filename
from photo ph
where po.globalid = ph.rel_globalid
limit 1
) q on true
;
使用krokodilko的答案,我进行了一个新的SQL查询,没有左连接横向
,因为我使用的是PostgreSQL 9.2(没有左连接横向
)
我唯一不喜欢的是OVER(PARTITION)
在几乎每个字段中在内部连接中使用krokodilko的答案,我做了一个新的SQL查询,没有左连接横向,因为我使用的是PostgreSQL 9.2(没有左连接横向
)
我唯一不喜欢它的是在内部连接中的几乎每个字段中的上(分区)
!左侧连接对我来说是新的!不幸的是,它与这里运行的postgresql 9.2不兼容(不要问我为什么运行这个版本)!tks!左侧连接对我来说是新的!不幸的是,它与这里运行的postgresql 9.2不兼容(不要问我为什么运行这个版本)!
select *
from point po
left join lateral
(
select first_value( date ) over( order by ph.date) as first_photo_date,
first_value( filename ) over( order by ph.date) as first_photo_filename,
case when count(*) over () > 1
then last_value( date ) over( order by ph.date)
end as last_photo_date,
case when count(*) over () > 1
then last_value( filename ) over( order by ph.date)
end as last_photo_filename
from photo ph
where po.globalid = ph.rel_globalid
limit 1
) q on true
;
SELECT DISTINCT
po.km,
po.globalid,
po.lat,
po."long",
ph.fp_date,
ph.fp_filename,
ph.lp_date,
ph.lp_filename
FROM
point po
INNER JOIN
(
SELECT DISTINCT
rel_globalid,
first_value(date) OVER (PARTITION BY ph.rel_globalid) AS fp_date,
first_value(filename) OVER (PARTITION BY ph.rel_globalid) AS fp_filename,
CASE WHEN count(*) OVER (PARTITION BY ph.rel_globalid) > 1 THEN
last_value(date) OVER (PARTITION BY ph.rel_globalid)
END AS lp_date,
CASE WHEN count(*) OVER (PARTITION BY ph.rel_globalid) > 1 THEN
last_value(filename) OVER (PARTITION BY ph.rel_globalid)
END AS lp_filename
FROM
photo ph
ORDER BY
rel_globalid
) ph
ON ph.rel_globalid = po.globalid