Group by select based on OR condition

时间:2017-05-16 09:37:25

标签: mysql sql sql-server oracle postgresql

After using UNION with two select queries, I'm getting following results

UserId    Name    Status
------   ------  --------
1   User1   Active
2   User2   Active
1   User1   InActive
3   User3   InActive

But the expected results is

UserId Name Status
---------------------
1   User1   Active
2   User2   Active
3   User3   InActive

Here what I need is, I want to group by column Id and get status as Active if any one result is active. How to form a SQL query for this?

Can anyone suggest query for any one of the following DB?

  1. MSSQL
  2. Oracle
  3. MySQL
  4. PostgreSQL

Edit:

This is the query I've tried in PostgreSQL

(SELECT DISTINCT User.Id,User.DisplayName,AppAccessToUsers.IsActive='1' AND User.IsActive='1' AS IsStatusActive 
FROM Applications Left JOIN AppAccessToUsers ON (Applications.Id=AppAccessToUsers.ApplicationId) 
Left JOIN User ON (AppAccessToUsers.UserId=User.Id) WHERE Applications.ClientId='e7e66c1b-b3b8-4ffb-844b-fc4840803265') 
UNION 
(SELECT DISTINCT User.Id,User.DisplayName,AppAccessToGroups.IsActive='1' AND Group.IsActive='1' AND UserGroup.IsActive='1' AND User.IsActive='1' AS IsStatusActive 
FROM Applications Left JOIN AppAccessToGroups ON (Applications.Id=AppAccessToGroups.ApplicationId) 
Left JOIN Group ON (AppAccessToGroups.GroupId=Group.Id) Left JOIN UserGroup ON (Group.Id=UserGroup.GroupId) 
Left JOIN User ON (UserGroup.UserId=User.Id) WHERE Applications.ClientId='e7e66c1b-b3b8-4ffb-844b-fc4840803265')

8 个答案:

答案 0 :(得分:1)

使用此查询

SELECT  UserId
        ,Name
        ,CASE WHEN min(status) = 'Active' THEN 'Active' ELSE 'InActive' END
FROM users GROUP BY UserId,Name

答案 1 :(得分:1)

我会这样做,假设a)你的表被称为t1和t2(根据你的实际表名修改)和b)两个表中每个用户ID的名称是相同的 - 即。对于userid = 1,两个表都具有相同的名称:

SELECT userid,
       NAME,
       MIN(status)
FROM   (SELECT userid, NAME, status FROM t1
        UNION ALL
        SELECT userid, NAME, status FROM t2)
GROUP BY userid, NAME;

这适用于Oracle,我很确定它可以在您提到的其他数据库平台中运行。

N.B。我使用了MIN(status),因为您似乎希望状态为Active以覆盖非活动状态,而A则出现在字母表中。

答案 2 :(得分:0)

对于postgres,您可以使用CASEbool_or,例如:

t=# with a(i,n,b) as (
  values (1,'a','active'), (1,'a','inactive'), (2,'b','inactive'), (2,'b','inactive')
)
select i,n,case when bool_or(b = 'active') then 'active' else 'inactive' end
from a
group by i,n
;
 i | n |   case
---+---+----------
 1 | a | active
 2 | b | inactive
(2 rows)

答案 3 :(得分:0)

在Sql-server中,您可以像这样使用group byRow_number

DECLARE @SampleData AS TABLE
(
   UserId    int,
   Name   varchar(20),
   Status varchar(10)
)

INSERT INTO @SampleData
(
   UserId,Name,Status
)
VALUES
(1,'User1', 'Active'),
(2,'User2', 'Active'),
(1,'User1', 'InActive'),
(3,'User3', 'InActive')

-- use row_number
;WITH temp AS
(
   SELECT *, row_number() OVER(PARTITION BY sd.UserId ORDER BY sd.Status ) AS Rn
   FROM @SampleData sd
)
SELECT t.UserId, t.Name, t.Status
FROM temp t WHERE t.Rn = 1

--or use group by
SELECT sd.UserId, sd.Name, min(sd.Status) AS status 
FROM @SampleData sd
GROUP BY sd.UserId, sd.Name

结果:

UserId  Name    Status
1      User1    Active
2      User2    Active
3      User3    InActive

答案 4 :(得分:0)

对于MS Sql Server,您可以尝试row_number

;with cte as (
select top 1 with ties * from
( select * from #youruser
    union all
  select * from #youruser) a
order by row_number() over (partition by userid order by [status] desc) 
) select * from cte where status = 'Active'

答案 5 :(得分:0)

select your_table.* from your_table
inner join (
    select UserId, min(Status) as st from your_table
    group by UserId
) t
on your_table.UserId = t.UserId and your_table.Status = t.st

注意:如果相同的UserId可以有相同的Status超过1次,那么这会返回重复的结果。

答案 6 :(得分:0)

;With cte (UserId, Name,Status)
AS
(
SELECT 1,'User1','Active'   Union all
SELECT 2,'User2','Active'   Union all
SELECT 1,'User1','InActive' Union all
SELECT 3,'User3','InActive'
)
SELECT UserId
    ,NAME
    ,[Status]
FROM (
    SELECT *
        ,ROW_NUMBER() OVER (
            PARTITION BY UserId
            ,NAME ORDER BY STATUS
            ) AS Seq
    FROM cte
    ) dt
WHERE dt.Seq = 1

输出

UserId  Name    Status
-----------------------
1       User1   Active
2       User2   Active
3       User3   InActive

答案 7 :(得分:0)

另一种方法:

Note : Group by is to remove duplicate

select 
A.USERID, A.NAME,A.STATUS
from TAB_1 A
LEFT JOIN
(SELECT * FROM TAB_1 WHERE STATUS='Active') B
ON A.USERID=B.USERID
WHERE
( B.STATUS IS NULL OR A.STATUS=B.STATUS)
GROUP BY A.USERID, A.NAME,A.STATUS
ORDER BY A.USERID
;