【问题标题】:Group by select based on OR condition根据 OR 条件按选择分组
【发布时间】:2017-10-15 07:33:00
【问题描述】:

将 UNION 与两个选择查询一起使用后,我得到以下结果

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

但预期的结果是

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

我需要的是,如果任何一个结果处于活动状态,我想按列 Id 分组并获得状态为活动。如何为此形成 SQL 查询?

任何人都可以建议查询以下任一数据库吗?

  1. MSSQL
  2. 甲骨文
  3. MySQL
  4. PostgreSQL

编辑:

这是我在 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')

【问题讨论】:

  • 你尝试过什么查询
  • 你根据什么来决定一个用户是否同时拥有活跃和不活跃的记录,那么应该以哪一个为准?
  • 他们中的任何一个?你会根据你在这里得到的答案选择 db 吗?
  • @Shadow 如果用户有至少一个活动记录,我想将状态设为活动
  • @jarlh 我正在使用上面列出的所有数据库。您可以为任何人推荐数据库

标签: mysql sql sql-server oracle postgresql


【解决方案1】:

对于 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)

【讨论】:

  • bool_or(b='active')
【解决方案2】:

在 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

【讨论】:

    【解决方案3】:

    如果是 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'
    

    【讨论】:

      【解决方案4】:
      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 次以上,则返回重复的结果。

      【讨论】:

        【解决方案5】:
        ;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
        

        【讨论】:

          【解决方案6】:

          使用这个查询,

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

          【讨论】:

            【解决方案7】:

            我会执行以下操作,假设 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,我很确定它适用于您提到的其他数据库平台。

            注意我使用了MIN(status),因为您似乎希望 Active 状态覆盖 Inactive 状态,并且 A 在字母表中位于 I 之前。

            【讨论】:

              【解决方案8】:

              另一种方法:

              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
              ;
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2022-12-20
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2019-02-11
                • 2018-05-18
                • 1970-01-01
                相关资源
                最近更新 更多