postgresql 选择最多为某个ID的有序行

lvjbypge  于 2023-02-22  发布在  PostgreSQL
关注(0)|答案(5)|浏览(158)
INSERT INTO "public"."catalog_element" 
("id", "catalogue_id", "element_id", "weight") VALUES
(1,100,1,0),
(2,100,2,1),
(3,100,3,2),
(4,10,1,0),
(5,10,5,0),
(6,10,6,1),
(7,100,7,1);

假设我们有一个包含catalog *- to -* element匹配行的Postgres表,这些行是加权的,如下所示
| 身份证|目录标识|元素标识|重量|
| - ------|- ------|- ------|- ------|
| 1个|一百|1个|无|
| 第二章|一百|第二章|1个|
| 三个|一百|三个|第二章|
| 四个|十个|1个|无|
| 五个|十个|五个|无|
| 六个|十个|六个|1个|
| 七|一百|七|1个|
我尝试编写一个查询,返回绑定到特定catalog_id的记录,按权重排序,范围从第一个到具有特定element_id的一个。
例如,catalog_id = 100按权重对DESC排序,并且每隔一行,直到element_id = 7满足,最终得到以下结果:
| 身份证|目录标识|元素标识|重量|
| - ------|- ------|- ------|- ------|
| 三个|一百|三个|第二章|
| 第二章|一百|第二章|1个|
| 七|一百|七|1个|

wlp8pajw

wlp8pajw1#

您可以使用子查询获取所需的权重,然后选择大于该权重的列

SELECT
"id", "catalogue_id", "element_id", "weight"
FROM catalog_element
WHERE "catalogue_id" = 100 AND weight >= (SELECT weight FROM catalog_element WHERE "element_id" = 7)

| 身份证|目录标识|元素标识|重量|
| - ------|- ------|- ------|- ------|
| 第二章|一百|第二章|1个|
| 三个|一百|三个|第二章|
| 七|一百|七|1个|

SELECT 3

fiddle

5ktev3wc

5ktev3wc2#

我不确定你是否认为我的解决方案不那么笨拙,它确实避免了自连接,这应该会为大型表带来更好的性能。

select * from (
  select
    coalesce(lag(max_flag,1) over (order by weight desc, flag),0) lmf,
    wmf.*
  from (
    select 
      max(flag) over( order by weight desc, flag) max_flag,
      wf.* 
    from (
      select
        case
          when element_id = 7 then 1
          else 0
        end flag,
        ce.* 
      from catalog_element ce
      where catalogue_id = 100
    ) wf
  ) wmf
) wlmf
where lmf =0;

收益率
| 低频磁场|最大_标志|旗|身份证|目录标识|元素标识|重量|
| - ------|- ------|- ------|- ------|- ------|- ------|- ------|
| 无|无|无|三个|一百|三个|第二章|
| 无|无|无|第二章|一百|第二章|1个|
| 无|1个|1个|七|一百|七|1个|
使用以下设置

create table catalog_element (
 id integer, 
 catalogue_id integer, 
 element_id integer, 
 weight integer
);

INSERT INTO catalog_element 
(id, catalogue_id, element_id, weight) VALUES
(1,100,1,0),
(2,100,2,1),
(3,100,3,2),
(4,10,1,0),
(5,10,5,0),
(6,10,6,1),
(7,100,7,1);

虽然这样的声明看起来很吓人,但实际上并不难理解。
1.您使用的是analytic or windowing functions yourself, so I assume basic knowledge of their working
1.因为你不能直接嵌套这样的函数,所以我使用嵌套的选择,每一层嵌套添加一个函数,因此这样的语句应该从里到外读取。
1.* with_flag * 的最里面一个wf使用以下命令添加一个flag

case
     when element_id = 7 then 1
     else 0
 end flag

标记被截断的行。这发生在它自己的子选择中,因为我们在下一步中需要两次标记。
1.在wmf for * with_max_flag * 中,我们使用max(flag) over( order by weight desc, flag)来创建max_flag列,该列对于截止行之前的所有行都具有0。这并不是说我们也按flag排序,以便对于与截止行具有相同权重的那些行也具有0
1.现在我们几乎可以按行过滤了,但是我们希望包含从row中删除的行,所以我们使用lagmax_flag移动一行,并使用coalescenull的值转换为0,对于 * with_lag_max_flag *,这在wlmf中发生。
1.最后,我们只过滤掉需要的行。
生成的SQL语句看起来很笨拙,但它只访问数据一次,并且始终按照相同的标准排序。我对类似的、实际上更大的语句的经验是,它们执行得非常好。
View on DB Fiddle

ovfsdjhp

ovfsdjhp3#

使用LATERAL计算最大相关权重。取权重较大的所有行,仅取到element_id = 7为止具有该权重的行。对于element_id = 7,可能返回多行。定义额外的标准以选择单个element_id = 7行。

select "id", "catalogue_id", "element_id", "weight"
from catalog_element e
cross join lateral (
    SELECT max(e2.weight) maxw
    FROM catalog_element e2 
    WHERE e2."element_id" = 7 and e2.catalogue_id = e.catalogue_id 
) t 
where "catalogue_id" = 100 
   and weight >= t.maxw   
   and (weight > t.maxw or element_id <= 7)
order by weight desc, element_id
55ooxyrt

55ooxyrt4#

要在给定insert语句中的数据上选择最多为某个ID的有序行,可以使用以下SQL查询:

SELECT * FROM catalog_element
    WHERE id <= <max_id>
    ORDER BY catalogue_id ASC, weight ASC, element_id ASC;

替换<max_id>为要包含在结果中的最大ID值。此查询将从catalog_element表中选择ID值小于或等于指定的最大ID的所有行,并首先按catalog_id升序、然后按weight升序、最后按element_id升序对结果进行排序。
例如,如果要选择ID值小于或等于5的所有行,则查询应为:

SELECT * FROM catalog_element
WHERE id <= 5
ORDER BY catalogue_id ASC, weight ASC, element_id ASC;

这将返回以下行:

id  | catalogue_id | element_id | weight
----+-------------+------------+-------
1   | 100         | 1          | 0
2   | 100         | 2          | 1
3   | 100         | 3          | 2
4   | 10          | 1          | 0
5   | 10          | 5          | 0
kcwpcxri

kcwpcxri5#

我找到了做我想做的事的方法,但是太笨拙了

WITH ordered_catalogue_elements AS (
    SELECT *, ROW_NUMBER () OVER (ORDER BY weight DESC, id ASC)
    FROM catalogue
    WHERE 
        catalogue_id = 100
)
SELECT *
FROM ordered_catalogue_elements
WHERE row_number <= (
    SELECT row_number
    FROM ordered_catalogue_elements
    WHERE element_id = 7
);

相关问题