如果我有优先级列表,如何在 SQL 中选择中间值?

问题描述 投票:0回答:1

我公司中有几个组织已将分配给它们的“组类别”与个人优先级相关联。我有疑问

     ...      WHERE gc.priority_level = (SELECT MIN(gc_inner.priority_level)      ...), as first_category

    ...      WHERE gc.priority_level = (SELECT MAX(gc_inner.priority_level)     ...), as third_category

gc 优先级可以根据组织的不同而变化,有些只有 1 个优先级,而另一些则最多为 3 个,因此我需要能够找到位于最低优先级和最高优先级之间的潜在 secondary_category。

          (             
SELECT g.name             
FROM groups g             
INNER JOIN group_categories gc ON gc.id = g.group_category_id             INNER JOIN item_groups ig ON ig.group_id = g.id AND ig.item_id = i1."id"             WHERE gc.priority_level = (               
   SELECT MIN(gc_inner.priority_level)               
   FROM group_categories gc_inner               
   INNER JOIN item_groups ig_inner ON ig_inner.group_id = g.id 
   AND ig_inner.item_id = i1."id"               
   WHERE gc_inner.id = g.group_category_id AND gc_inner.type = 'item'             )                  
   AND gc.type = 'item'             
   LIMIT 1           
) AS "primary_item_category",             
(             
SELECT g.name             
FROM groups g             
INNER JOIN group_categories gc ON gc.id = g.group_category_id             
INNER JOIN item_groups ig ON ig.group_id = g.id 
AND ig.item_id = i1."id"             
WHERE gc.priority_level = (               
  SELECT MIN(gc_inner.priority_level)               
  FROM group_categories gc_inner               
  INNER JOIN item_groups ig_inner ON ig_inner.group_id = g.id 
  AND ig_inner.item_id = i1."id"               
  AND gc_inner.priority_level > (                 
    SELECT MIN(gc_inner2.priority_level)                 
    FROM group_categories gc_inner2                 
    INNER JOIN item_groups ig_inner2 ON ig_inner2.group_id = g.id 
    AND ig_inner2.item_id = i1."id"               )
    )             
  AND gc.type = 'item'             
  LIMIT 1           
) AS "second_item_category", 
(             
SELECT g.name             
FROM groups g             
INNER JOIN group_categories gc ON gc.id = g.group_category_id             
INNER JOIN item_groups ig ON ig.group_id = g.id 
AND ig.item_id = i1."id"             
WHERE gc.priority_level = (               
  SELECT MAX(gc_inner.priority_level)               
  FROM group_categories gc_inner               
  INNER JOIN item_groups ig_inner ON ig_inner.group_id = g.id 
  AND ig_inner.item_id = i1."id")             
AND gc.type = 'item'             
LIMIT 1           
) AS "third_item_category",
...

我在测试中设置了这个:`org = insert(:organization)

  group_category1 =     insert(:group_category, type: "organization", priority_level: 1, organization: org, name: "OrganizationCategory")    group_category2 =     insert(:group_category, type: "item", priority_level: 2, organization: org, name: "PrimaryItemCategory")    group_category3 =     insert(:group_category, type: "item", priority_level: 3, organization: org, name: "SecondItemCategory")    group_category4 =     insert(:group_category, type: "item", priority_level: 4, organization: org, name: "ThirdItemCategory")    org_group1 = Factory.insert(:group, group_category: group_category1, name: "org_group1")   org_group2 = Factory.insert(:group, group_category: group_category2, name: "org_group2")   org_group3 = Factory.insert(:group, group_category: group_category3, name: "org_group3")   org_group4 = Factory.insert(:group, group_category: group_category4, name: "org_group4")

所以我期待“org_group3”的返回,但在拉取 secondary_item_category 时却得到 nil,但所有其他类别都正确返回。

如果我将 secondary_item_category 更改为

        (             SELECT g.name             FROM groups g             INNER JOIN group_categories gc ON gc.id = g.group_category_id             INNER JOIN item_groups ig ON ig.group_id = g.id AND ig.item_id = i1."id"             WHERE gc.priority_level = (               SELECT priority_level               FROM (                 SELECT gc_inner.priority_level,                       ROW_NUMBER() OVER (ORDER BY gc_inner.priority_level) AS rn,                       COUNT(*) OVER () AS cnt                 FROM group_categories gc_inner                 INNER JOIN item_groups ig_inner ON ig_inner.group_id = g.id AND ig_inner.item_id = i1."id"                 WHERE gc_inner.id = g.group_category_id AND gc_inner.type = 'item'               ) subquery               WHERE rn = (cnt + 1) / 2             )             AND gc.type = 'item'             LIMIT 1           ) AS "second_item_category",

然后返回 org_group2 而不是 org_group3。

sql postgresql sorting elixir ecto
1个回答
0
投票

“项目”类型存在一个、两个或三个组类别。您想按priority_level 对它们进行排序。对于每个组类别,您要选择其中一个组名称,并根据其优先级排名将其称为first_category、second_category 和third_category。

您可以使用窗口函数来做到这一点

DENSE_RANK
:

WITH
  ranked AS
  (
    SELECT
      g.name, 
      DENSE_RANK() OVER (ORDER BY gc.priority_level) AS rn
    FROM groups g             
    INNER JOIN group_categories gc ON gc.id = g.group_category_id             
    WHERE gc.type = 'item'             
  )
SELECT
  ANY_VALUE(name) FILTER (WHERE rn = 1) AS first_category,
  ANY_VALUE(name) FILTER (WHERE rn = 2) AS second_category,
  ANY_VALUE(name) FILTER (WHERE rn = 3) AS third_category
FROM ranked;

这是针对多个类别类型的相同查询:

WITH
  ranked AS
  (
    SELECT
      gc.type,
      g.name, 
      DENSE_RANK() OVER (PARTITION BY gc.type ORDER BY gc.priority_level) AS rn
    FROM groups g             
    INNER JOIN group_categories gc ON gc.id = g.group_category_id             
  )
SELECT
  type,
  ANY_VALUE(name) FILTER (WHERE rn = 1) AS first_category,
  ANY_VALUE(name) FILTER (WHERE rn = 2) AS second_category,
  ANY_VALUE(name) FILTER (WHERE rn = 3) AS third_category
FROM ranked
GROUP BY type
ORDER BY type;
© www.soinside.com 2019 - 2024. All rights reserved.