Postgresql 如何在最大点间距(SQL)中找到最小值和最大值
目前,我有一个PostgreSQL数据库(和一个结构几乎相同的SQL Server数据库),其中包含一些数据,如下例:Postgresql 如何在最大点间距(SQL)中找到最小值和最大值,postgresql,Postgresql,目前,我有一个PostgreSQL数据库(和一个结构几乎相同的SQL Server数据库),其中包含一些数据,如下例: +----+---------+-----+ | ID | Name | Val | +----+---------+-----+ | 01 | Point A | 0 | | 02 | Point B | 050 | | 03 | Point C | 075 | | 04 | Point D | 100 | | 05 | Point E | 200 | | 06 |
+----+---------+-----+
| ID | Name | Val |
+----+---------+-----+
| 01 | Point A | 0 |
| 02 | Point B | 050 |
| 03 | Point C | 075 |
| 04 | Point D | 100 |
| 05 | Point E | 200 |
| 06 | Point F | 220 |
| 07 | Point G | 310 |
| 08 | Point H | 350 |
| 09 | Point I | 420 |
| 10 | Point J | 550 |
+----+---------+-----+
ID = PK (auto increment);
Name = unique;
Val = unique;
现在,假设我只有点F(220),我想找到数据之间最大距离小于100的最小值和最大值
因此,我的结果必须返回:
- 最低:点E(200)
- 最大:点I(420)
- 寻找最低值:
Initial value = Point F (220); Look for the lower closest value of Point F (220): Point E (200); 200(E) < 220(F) = True; 220(F) - 200(E) < 100 = True; Lowest value until now = Point E (200) Repeat Look for the lower closest value of Point E (200): Point D (100); 100(D) < 200(E) = True; 200(E) - 100(D) < 100 = False; Lowest value = Point E (200); Break;
Initial value = Point F (220); Look for the biggest closest value of Point F (220): Point G (310); 310(G) > 220(F) = True; 310(G) - 220(F) < 100 = True; Biggest value until now = Point G (310) Repeat Look for the biggest closest value of Point G (310): Point H (350); 350(H) > 310(G) = True; 350(H) - 310(G) < 100 = True; Biggest value until now = Point H (350) Repeat Look for the biggest closest value of Point H (350): Point I (420); 420(I) > 350(H) = True; 420(I) - 350(H) < 100 = True; Biggest value until now = Point I (420) Repeat Look for the biggest closest value of Point I (420): Point J (550); 550(J) > 420(I) = True; 550(J) - 420(I) < 100 = False; Biggest value Point I (420); Break;
初始值=点F(220); 查找点F(220)的最近下限值:点E(200); 200(E)<220(F)=正确;220(F)-200(E)<100=正确; 迄今为止的最低值=E点(200) 重复 查找点E(200)的最近下限值:点D(100); 100(D)<200(E)=正确;200(E)-100(D)<100=假; 最低值=E点(200);打破
- 寻找最大价值:
Initial value = Point F (220); Look for the lower closest value of Point F (220): Point E (200); 200(E) < 220(F) = True; 220(F) - 200(E) < 100 = True; Lowest value until now = Point E (200) Repeat Look for the lower closest value of Point E (200): Point D (100); 100(D) < 200(E) = True; 200(E) - 100(D) < 100 = False; Lowest value = Point E (200); Break;
Initial value = Point F (220); Look for the biggest closest value of Point F (220): Point G (310); 310(G) > 220(F) = True; 310(G) - 220(F) < 100 = True; Biggest value until now = Point G (310) Repeat Look for the biggest closest value of Point G (310): Point H (350); 350(H) > 310(G) = True; 350(H) - 310(G) < 100 = True; Biggest value until now = Point H (350) Repeat Look for the biggest closest value of Point H (350): Point I (420); 420(I) > 350(H) = True; 420(I) - 350(H) < 100 = True; Biggest value until now = Point I (420) Repeat Look for the biggest closest value of Point I (420): Point J (550); 550(J) > 420(I) = True; 550(J) - 420(I) < 100 = False; Biggest value Point I (420); Break;
初始值=点F(220); 查找点F(220)的最大最近值:点G(310); 310(G)>220(F)=正确;310(G)-220(F)<100=真; 迄今为止的最大值=点G(310) 重复 查找点G(310)的最大最近值:点H(350); 350(H)>310(G)=正确;350(H)-310(G)<100=正确; 迄今为止的最大值=H点(350) 重复 查找点H(350)的最大最近值:点I(420); 420(I)>350(H)=正确;420(I)-350(H)<100=真; 迄今为止的最大值=点I(420) 重复 寻找点I(420)的最大最近值:点J(550); 550(J)>420(I)=正确;550(J)-420(I)<100=假; 最大值点I(420);打破
point_和
):
SELECT
id, name, val,
lag(val) OVER(ORDER BY id) AS prev_val,
lead(val) OVER(ORDER BY id) AS next_val
FROM
points
产生:
| id | name | val | prev_val | next_val |
|----|---------|-----|----------|----------|
| 1 | Point A | 0 | (null) | 50 |
| 2 | Point B | 50 | 0 | 75 |
| 3 | Point C | 75 | 50 | 100 |
| 4 | Point D | 100 | 75 | 200 |
| 5 | Point E | 200 | 100 | 220 |
| 6 | Point F | 220 | 200 | 310 |
| 7 | Point G | 310 | 220 | 350 |
| 8 | Point H | 350 | 310 | 420 |
| 9 | Point I | 420 | 350 | 550 |
| 10 | Point J | 550 | 420 | (null) |
窗口函数用于从表中获取上一个值和下一个值(按id排序,不按任何分区)
接下来,我们制作第二个表point_和
,它使用val
、prev_val
和Next_val
,计算到上一点的距离和到下一点的距离。这将通过以下选择进行计算:
SELECT
id, name, val, (val-prev_val) AS dist_to_prev, (next_val-val) AS dist_to_next
FROM
point_and_prev_next
这是执行后得到的结果:
| id | name | val | dist_to_prev | dist_to_next |
|----|---------|-----|--------------|--------------|
| 1 | Point A | 0 | (null) | 50 |
| 2 | Point B | 50 | 50 | 25 |
| 3 | Point C | 75 | 25 | 25 |
| 4 | Point D | 100 | 25 | 100 |
| 5 | Point E | 200 | 100 | 20 |
| 6 | Point F | 220 | 20 | 90 |
| 7 | Point G | 310 | 90 | 40 |
| 8 | Point H | 350 | 40 | 70 |
| 9 | Point I | 420 | 70 | 130 |
| 10 | Point J | 550 | 130 | (null) |
在这一点上,(从点“F”开始),我们可以通过以下查询得到第一个“错误点”(第一个未达到“到上一个点的距离”<100):
SELECT
max(id) AS first_wrong_up
FROM
point_and_dist_prev_next
WHERE
dist_to_prev >= 100
AND id <= 6 -- 6 = Point F
以等效方式计算下降的第一个“错误点”
所有这些查询都可以使用(WITH
查询)组合在一起,您可以得到:
WITH point_and_dist_prev_next AS
(
SELECT
id, name, val,
val - lag(val) OVER(ORDER BY id) AS dist_to_prev,
lead(val) OVER(ORDER BY id)- val AS dist_to_next
FROM
points
),
first_wrong_up AS
(
SELECT
max(id) AS first_wrong_up
FROM
point_and_dist_prev_next
WHERE
dist_to_prev >= 100
AND id <= 6 -- 6 = Point F
),
first_wrong_down AS
(
SELECT
min(id) AS first_wrong_down
FROM
point_and_dist_prev_next
WHERE
dist_to_next >= 100
AND id >= 6 -- 6 = Point F
)
SELECT
(SELECT name AS "lowest value"
FROM first_wrong_up
JOIN points ON id = first_wrong_up),
(SELECT name AS "biggest value"
FROM first_wrong_down
JOIN points ON id = first_wrong_down) ;
你可以在网上查一下
注:假设
id
列始终在增加。如果不是,则必须使用val
列(显然,假设它一直在增长)。这可以通过使用和一些工作来完成
以一步一步的方式,您可以从以下选择定义一个表开始(我们称之为point_和
):
SELECT
id, name, val,
lag(val) OVER(ORDER BY id) AS prev_val,
lead(val) OVER(ORDER BY id) AS next_val
FROM
points
产生:
| id | name | val | prev_val | next_val |
|----|---------|-----|----------|----------|
| 1 | Point A | 0 | (null) | 50 |
| 2 | Point B | 50 | 0 | 75 |
| 3 | Point C | 75 | 50 | 100 |
| 4 | Point D | 100 | 75 | 200 |
| 5 | Point E | 200 | 100 | 220 |
| 6 | Point F | 220 | 200 | 310 |
| 7 | Point G | 310 | 220 | 350 |
| 8 | Point H | 350 | 310 | 420 |
| 9 | Point I | 420 | 350 | 550 |
| 10 | Point J | 550 | 420 | (null) |
窗口函数用于从表中获取上一个值和下一个值(按id排序,不按任何分区)
接下来,我们制作第二个表point_和
,它使用val
、prev_val
和Next_val
,计算到上一点的距离和到下一点的距离。这将通过以下选择进行计算:
SELECT
id, name, val, (val-prev_val) AS dist_to_prev, (next_val-val) AS dist_to_next
FROM
point_and_prev_next
这是执行后得到的结果:
| id | name | val | dist_to_prev | dist_to_next |
|----|---------|-----|--------------|--------------|
| 1 | Point A | 0 | (null) | 50 |
| 2 | Point B | 50 | 50 | 25 |
| 3 | Point C | 75 | 25 | 25 |
| 4 | Point D | 100 | 25 | 100 |
| 5 | Point E | 200 | 100 | 20 |
| 6 | Point F | 220 | 20 | 90 |
| 7 | Point G | 310 | 90 | 40 |
| 8 | Point H | 350 | 40 | 70 |
| 9 | Point I | 420 | 70 | 130 |
| 10 | Point J | 550 | 130 | (null) |
在这一点上,(从点“F”开始),我们可以通过以下查询得到第一个“错误点”(第一个未达到“到上一个点的距离”<100):
SELECT
max(id) AS first_wrong_up
FROM
point_and_dist_prev_next
WHERE
dist_to_prev >= 100
AND id <= 6 -- 6 = Point F
以等效方式计算下降的第一个“错误点”
所有这些查询都可以使用(WITH
查询)组合在一起,您可以得到:
WITH point_and_dist_prev_next AS
(
SELECT
id, name, val,
val - lag(val) OVER(ORDER BY id) AS dist_to_prev,
lead(val) OVER(ORDER BY id)- val AS dist_to_next
FROM
points
),
first_wrong_up AS
(
SELECT
max(id) AS first_wrong_up
FROM
point_and_dist_prev_next
WHERE
dist_to_prev >= 100
AND id <= 6 -- 6 = Point F
),
first_wrong_down AS
(
SELECT
min(id) AS first_wrong_down
FROM
point_and_dist_prev_next
WHERE
dist_to_next >= 100
AND id >= 6 -- 6 = Point F
)
SELECT
(SELECT name AS "lowest value"
FROM first_wrong_up
JOIN points ON id = first_wrong_up),
(SELECT name AS "biggest value"
FROM first_wrong_down
JOIN points ON id = first_wrong_down) ;
你可以在网上查一下
注:假设
id
列始终在增加。如果不是,则必须使用val
列(显然,假设它一直在增长)。如何识别“初始值”?您是否有它的值(Val
,即您的示例中的220
),它的ID
(06
)或它的名称(OFC,仅当它唯一时)?ID
是一个自动递增的数字Val
是唯一的,name
也是唯一的!我最初只有ID
。从您对删除答案的评论(t不是点F和最小值和最大值之间小于100的间隔!它是上一点和下一点之间的间隔)我认为这是一个特殊问题。您如何识别“初始值”?您是否有它的值(Val
,即您的示例中的220
),它的ID
(06
)或它的名称(OFC,仅当它唯一时)?ID
是一个自动递增的数字Val
是唯一的,name
也是唯一的!最初我只有ID
。从你对删除答案的评论来看(在点F和最小值和最大值之间的间隔不是小于100!在上一点和下一点之间),我认为这是一个特殊问题。tks!我还没有测试(SQLFIDLE现在不工作)!但是我喜欢“逐步时尚”中的解释:在这个SQL中有一个“bug”。如果不搜索点F的“最小值和最大值”,而是搜索点A、B、C或D的较小值和较大值,则最小值将为空。如果我搜索点J的最大值,也会发生同样的情况。为了纠正这个“错误”,我只是在中将条件更改为:(dist\u To\u prev>=100或dist\t