2012-07-24 94 views
2

我們正在監視網絡設備。 設備可能出現在多個交換機上。如果col1值退出兩次且col2不爲空,則選擇行

我們想要過濾那些在上行鏈路/端口通道上的設備,以防它出現在另一個端口上。所有其他設備都被選中。

假設表的樣子:

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 

的入門玉簪,交換機2,寶需要被過濾掉,因爲它出現在另一個端口上爲好。

現在的問題是如何編寫一個有效的查詢。

在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查詢?

回答

0

不存在應大於相關COUNT(*)快

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

UPDATE:,如果你認爲加入版本將有更好的表現:

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。哦,那是什麼解釋。

+0

我喜歡這個SQL已經好多了。但有沒有辦法避免子查詢(例如與連接/臨時表) – 2012-07-24 09:50:22

+0

@ThorstenNiehues您可以給連接查詢一槍嗎? – 2012-07-24 11:13:12

+0

非常感謝 - 看起來很棒。我會在今天/明天測試這兩個版本,讓你知道。 – 2012-07-24 13:23:06

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 
+0

此SQL語句僅選擇端口通道上的設備。必須選擇所有設備。如果有重複的主機,則必須忽略端口通道上的主機。 – 2012-07-24 10:04:43

+0

好的。看到我編輯的答覆 – Madhivanan 2012-07-24 12:41:06

0

假設有一個主機/開關組合至多一個端口,則可以通過使用組:

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 

如果有支持窗口函數的數據庫,則可以使用:

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 
相關問題