【问题标题】:Select row if col1 value exits twice and col2 is not null如果 col1 值退出两次并且 c​​ol2 不为空,则选择行
【发布时间】:2012-07-24 09:14:40
【问题描述】:

我们正在监控网络设备。 一个设备可能出现在多个开关上。

我们想要过滤掉那些在上行链路/端口通道上的设备,以防它也出现在另一个端口上。已选择所有其他设备。

假设表格如下:

HOST,  SWITCH,  PORT
HostA, Switch1, 01
HostB, Switch1, 02
HostA, Switch2, Po  - Po is portchannel / uplink
HostC, Switch2, Po  - Po is portchannel / uplink

期望的输出:

HostA, Switch1, 01
HostB, Switch1, 02
HostC, Swtich2, Po  - is only on an uplink / so that is OK

Entry HostA, Switch2, Po 需要过滤掉,因为它也出现在另一个端口上。

现在的问题是如何编写有效的查询。

在 SQL 术语中,我们希望选择除 HOST 出现两次的行之外的所有行。然后我们只想要 PORT 不是 'Po' 的那一行

由于子查询,我们当前的查询很慢!? 我假设子查询正在创建一个笛卡尔积 - 对吧?

SELECT * FROM devices t1
WHERE NOT ((Port = 'Po') AND 
      ((Select count(*) from table t2 where t1.host=t2.host AND NOT Port='Po') > 0))

问题又是如何编写更快的 SQL 查询??

【问题讨论】:

    标签: sql performance select subquery informix


    【解决方案1】:
    SELECT HOST as HOST,  SWITCH,  PORT from table 
    WHERE port<>'po' 
    UNION ALL
    SELECT MAX(HOST) as HOST,  SWITCH,  PORT from table
    WHERE port='po'
    GROUP BY SWITCH,  PORT 
    

    【讨论】:

    • 此 SQL 语句仅选择端口通道上的设备。必须选择所有设备。如果存在重复的主机,则必须忽略端口通道上的主机。
    【解决方案2】:

    不存在应该比相关计数(*)更快

    select *
      from devices t1
     where (port <> 'Po'
            or not exists (select null
                             from devices t2
                            where t2.host = t1.host
                              and t2.Port <> 'Po')
           )
    

    更新:如果您认为加入版本会表现更好:

    select t1.*
      from devices t1
      left join devices t2
        on t1.host = t2.host
       and t2.port <> 'Po'
     where (t1.port <> 'Po'
        or t2.port is null)
    

    查询自连接设备表,从第二个实例中删除 Po。然后它继续选择所有非 Po 和 Po 而不匹配非 Po。哦,好解释。

    【讨论】:

    • 我已经更喜欢那个 SQL 了。但是有没有办法避免子查询(例如使用连接/临时表)
    • @ThorstenNiehues 你能试一下加入查询吗?
    • 非常感谢 - 看起来不错。我将在今天/明天测试这两个版本并通知您。
    • 运行时间:1. 选择计数:3 秒 - 2. “不存在”(您的第一篇帖子)8 秒 - 3. “左连接”(更新帖子)0.2 秒。数据库是 Informix
    • @ThorstenNiehues 感谢您提供信息。我永远不会期望 exists() 比 count(*) 慢 - 好吧,这不是我第一次错了 :-)
    【解决方案3】:

    假设主机/交换机组合上最多有一个端口,您可以使用 group by:

    select HOST, SWITCH,
           (case when max(case when PORT <> 'Po' then 1 else 0 end) = 1
                 then max(case when PORT <> 'Po' then port end)
                 else 'Po'
            end) port
    from t
    group by host, switch
    

    如果你有支持windows功能的数据库,可以使用:

    select t.host, t.switch, t.port
    from (select t.*,
                 sum(isPo) over (partition by host, switch) as numPo,
                 count(*) over (partition by host, switch) as numAll
          from (select t.*,
                       (case when port = 'po' then 1 else 0 end) as isPo
                from t
               ) t
         ) t
    where numPo = numAll or -- all are Po
          (port <> 'Po')    -- remove any other Pos
    

    【讨论】:

      猜你喜欢
      • 2013-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-10
      相关资源
      最近更新 更多