如何从一列中选择仅包含另一列中的特定值而没有其他值的值?

时间:2019-08-01 17:15:18

标签: sql postgresql

我有一个pgsql模式,该模式的表中有两列:id和status。状态值是varchar类型,范围从'1'到'6'。我想选择仅具有特定状态的id的值,确切地说,一个id仅具有一个状态('1'),然后另一个具有两个值('1'和s'2'),然后另一个仅具有三个值(' 1”,“ 2”和“ 3”)等等。

这是用于pgsql数据库的。我曾尝试使用内部查询与同一张表联接。

select *
from srt s
join ( select id
       from srt
       group by id
       having count(distinct status) = 2
     ) t on t.id = s.id
where srt.status in ('1', '2')
limit 10

我用它来获取仅具有状态值1和2(并且没有任何具有状态值3、4、5、6的行)的ID,但是没有得到预期的结果

预期结果将是这样

id  status
123 1
234 1
234 2
345 1
345 2
345 3
456 1
456 2
456 3
456 4
567 1
567 2
567 3
567 4
567 5
678 1
678 2
678 3
678 4
678 5
678 6

3 个答案:

答案 0 :(得分:0)

在子查询中移动您的where条件-

select *
from srt s
join ( select id
       from srt
       where status in ('1', '2')
       group by id
       having count(distinct status) = 2
     ) t on t.id = s.id
limit 10

答案 1 :(得分:0)

要标识具有连续状态的ID,您可以执行以下操作:

select id, max(status) as max_status
from srt s
group by id
having min(status) = 1 and
       max(status::int) = count(*);

然后,您可以使用distinct on将其缩小为一个示例,并使用join来获得结果:

select s.*
from srt s join
     (select distinct on (max(status)) id, max(status) as max_status
      from srt s
      group by id
      having min(status) = 1 and
             max(status::int) = count(*)
      order by max_status asc
     ) ss
     on ss.id = s.id
order by ss.max_status, s.status;

答案 2 :(得分:0)

这是一个棘手的问题。我的解决方案是首先指定您要匹配的“目标状态”列表:

with target_statuses(s) as ( values (1),(2),(3) )

然后将您的srt表加入其中并计算按id分组的出现次数。

with target_statuses(s) as ( values (1),(2),(3) )
select id, count(*), row_number() OVER (partition by count(*) order by id) rownum
    from srt
    join target_statuses on status=s
    group by id
)

此查询还捕获行号,稍后我们将使用该行号将其限制为具有一个匹配项的第一个id,具有两个匹配项的第一个id,等等。请注意order by子句...我假设您在每种情况下都首先需要按字母顺序排列的最低编号,但是您可以更改它。

由于您无法将窗口函数放在HAVING子句中,因此我将整个结果包装在ids_and_counts_of_statuses处,并执行后续查询,并将其与srt重新合并表以输出它:

with ids_and_counts_of_statuses as(

with target_statuses(s) as ( values (1),(2),(3) )
select id, count(*), row_number() OVER (partition by count(*) order by id) rownum
    from srt
    join target_statuses on status=s
    group by id
)
select srt.id, srt.status
from ids_and_counts_of_statuses
join srt on ids_and_counts_of_statuses.id=srt.id
where rownum=1;

请注意,我只是将您的varchar值更改为整数,因此我不必键入太多标点符号。它可以工作,下面是一个示例:https://www.db-fiddle.com/f/wwob31uiNgr9aAkZoe1Jgs/0