【问题标题】:How do you grouby and check if group contains 2 or more of the given values?您如何分组并检查组是否包含 2 个或更多给定值?
【发布时间】:2019-06-15 04:51:55
【问题描述】:

我有一个带有建筑物名称的表,例如 A、B、C。这些建筑物名称可以重复。我有另一列有发言权。例如第 1 层,第 2 层。同样,每个建筑物都可以有多个第 1 层。第三列有对象存在,如电视、砖块、风扇。 我想检查建筑物与相应楼层的每个组合,例如 A 楼 - 1 楼,A 楼 - 2 楼,如果存在对象“砖”,则“墙”必须存在。

示例数据: 对于每个建筑物和位置,如果存在“WALL”,则必须存在“WINDOW”、“WINDOW1”或“WINDOW2”,ELSE FLAG

BUILDING  LOCATION  OBJECT   
A         FLOOR1    WINDOW1  
A         FLOOR1    WINDOW  
A         FLOOR1    WINDOW2 
A         FLOOR2    WALL  
B         FLOOR1    WALL  
C         FLOOR1    WALL  
C         FLOOR1    WINDOW

期望的输出

BUILDING  LOCATION  ACTION    
A         FLOOR2    FLAG
B         FLOOR1    FLAG

我尝试过使用 GROUP BY、DISTINCT、WHERE EXISTS,但我似乎无法提出正确的逻辑。

【问题讨论】:

  • @forpas 这是新问题!
  • 你的previous question有什么不同?
  • @PaulSpiegel 我想比较以检查 Window、Window1、Window2 等值的列表。至少应该存在一个。我已经更新了上一个。但是回到最初的问题并创建了这个
  • 我不明白“DESIRED OUPUT”如何对应于“对于每个建筑物和位置,如果存在'WALL','WINDOW','WINDOW1'或'WINDOW2'必须存在,ELSE FLAG ”。另外 - “ELSE FLAG”是什么意思?
  • 对于 A - FLOOR1,没有墙,所以没关系。对于 A-FLOOR2,存在一堵墙,因此必须存在任何一个窗户。但它不会让您选择该记录并在新列中添加“FLAG”。 B FLOOR1 相同。在 C FLOOR 1 的情况下,有一面墙,但也有一个窗户,因此不需要标记。 @PaulSpiegel

标签: mysql


【解决方案1】:

不存在:

select distinct t.building, t.location, 'FLAG' action
from tablename t
where object = 'WALL'
and not exists (
  select 1 from tablename
  where building = t.building and location = t.location
  and object like 'WINDOW%'
)

请参阅demo
结果:

| building | location | action |
| -------- | -------- | ------ |
| A        | FLOOR2   | FLAG   |
| B        | FLOOR1   | FLAG   |

【讨论】:

  • 我写的几乎一样,但结果与所需的输出不匹配,直到它在问题中得到修复。虽然我使用了rlike 'WINDOW[0-9]*'
  • * 表示零次或一次或多次。所以它也匹配'WINDOW'。不明白我的评论错了。我刚刚验证了您的解决方案是有效的。
  • @PaulSpiegel 你是对的。我误读了 rlike 模式(过多关注 sql server)。
【解决方案2】:

SQL DEMO

SELECT building, 
        location,  
        MAX(CASE WHEN object = 'WALL' THEN 1 ELSE 0 END) as has_walls,
        MAX(CASE WHEN object IN ('WINDOW', 'WINDOW1', 'WINDOW2') THEN 1 ELSE 0 END)  as has_windows
 FROM tablename
 GROUP BY building, location
 HAVING 
        has_walls <> has_windows;

因此,如果您有任何墙,MAX() 将返回 1,对于 windows 也是如此。

这带来了没有WINDOWSWALL,但也带来了没有WALLSWINDOWS

如果您需要更多改进,请告诉我

如果你想要 WALLS 而不需要 WINDOWS

 SELECT building, 
        location,  
        MAX(CASE WHEN object = 'WALL' THEN 1 ELSE 0 END) as has_walls,
        MAX(CASE WHEN object IN ('WINDOW', 'WINDOW1', 'WINDOW2') THEN 1 ELSE 0 END)  as has_windows
 FROM tablename
 GROUP BY building, location
 HAVING 
        has_walls > 0 
    AND has_windows = 0

【讨论】:

  • 您知道,您可以在 HAVING 子句中使用列别名吗?至少在 MySQL 中。
  • 嗯,确实是我在添加 HAVING 之后在 SELECT 上添加了列,以更清晰地显示结果。
【解决方案3】:

我实际上会以与 forpas 相同的方式编写查询。但这里有另一种方式:

select BUILDING, LOCATION, 'FLAG' as `ACTION`
from my_table
group by BUILDING, LOCATION
having bit_or(OBJECT = 'WALL') -- at least one OBJECT is 'WALL'
   and bit_and(OBJECT not rlike 'WINDOW[0-9]*') -- no OBJECT matches 'WINDOW[number]'

db-fiddle

它更短,但可能并不容易理解。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-06
    • 2017-10-17
    • 1970-01-01
    • 1970-01-01
    • 2015-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多