2010-09-07 96 views
3

這個question提醒了我一些關於整體比較的相關問題。鑑於:SQL比較集合,第二部分:如何連接集合集合

  1. 套一個collection,並且
  2. 一個probe設置

三個問題:

  1. 如何找到在collection匹配probe所有集合,元素的元素?
  2. 如何查找與probe s集合匹配的所有集合collection,而不使用顯式循環結構?你如何加入套裝?
  3. 這是關係部門嗎?如果不是,那是什麼?

我有一個體面的解決方案,問題1(見下文)。

對於問題2,我沒有合適的關係解決方案。任何接受者?

測試數據:

IF OBJECT_ID('tempdb..#elements') IS NOT NULL DROP TABLE #elements 
IF OBJECT_ID('tempdb..#sets') IS NOT NULL DROP TABLE #sets 

CREATE TABLE #sets (set_no INT, PRIMARY KEY (set_no)) 
CREATE TABLE #elements (set_no INT, elem CHAR(1), PRIMARY KEY (set_no, elem)) 

INSERT #elements VALUES (1, 'A') 
INSERT #elements VALUES (1, 'B') 
INSERT #elements VALUES (1, 'C') 
INSERT #elements VALUES (1, 'D') 
INSERT #elements VALUES (1, 'E') 
INSERT #elements VALUES (1, 'F') 
INSERT #elements VALUES (2, 'A') 
INSERT #elements VALUES (2, 'B') 
INSERT #elements VALUES (2, 'C') 
INSERT #elements VALUES (3, 'D') 
INSERT #elements VALUES (3, 'E') 
INSERT #elements VALUES (3, 'F') 
INSERT #elements VALUES (4, 'B') 
INSERT #elements VALUES (4, 'C') 
INSERT #elements VALUES (4, 'F') 
INSERT #elements VALUES (5, 'F') 

INSERT #sets SELECT DISTINCT set_no FROM #elements 

設置和解決問題1,設置查詢:

IF OBJECT_ID('tempdb..#probe') IS NOT NULL DROP TABLE #probe 
CREATE TABLE #probe (elem CHAR(1) PRIMARY KEY (elem)) 
INSERT #probe VALUES ('B') 
INSERT #probe VALUES ('C') 
INSERT #probe VALUES ('F') 

-- I think this works.....upvotes for anyone who can demonstrate otherwise 
SELECT set_no FROM #sets s 
WHERE NOT EXISTS (
    SELECT * FROM #elements i WHERE i.set_no = s.set_no AND NOT EXISTS (
    SELECT * FROM #probe p WHERE p.elem = i.elem)) 
AND NOT EXISTS (
    SELECT * FROM #probe p WHERE NOT EXISTS (
    SELECT * FROM #elements i WHERE i.set_no = s.set_no AND i.elem = p.elem)) 

設置問題2,無解:

IF OBJECT_ID('tempdb..#multi_probe') IS NOT NULL DROP TABLE #multi_probe 
CREATE TABLE #multi_probe (probe_no INT, elem CHAR(1) PRIMARY KEY (probe_no, elem)) 
INSERT #multi_probe VALUES (1, 'B') 
INSERT #multi_probe VALUES (1, 'C') 
INSERT #multi_probe VALUES (1, 'F') 
INSERT #multi_probe VALUES (2, 'C') 
INSERT #multi_probe VALUES (2, 'F') 
INSERT #multi_probe VALUES (3, 'A') 
INSERT #multi_probe VALUES (3, 'B') 
INSERT #multi_probe VALUES (3, 'C') 

-- some magic here..... 

-- result set: 
-- probe_no | set_no 
------------|-------- 
-- 1  | 4 
-- 3  | 2 
+0

給我一點彼得......這將需要一些思考...... – 2010-09-07 22:43:21

+0

@Joe,採取只要你想:) – 2010-09-07 23:06:40

+0

對於問題(2)你的意思是搜索所有在集合中設置至少匹配probe集合中的一個探針集合?即對於將設置4(與探針1匹配)和2(與探針3匹配)的給定設置 – CyberDude 2010-09-07 23:09:43

回答

2

好吧,讓我們一步解決問題2步:

(1)內部聯接組和探針對它們的單個元素。通過這種方式,我們將看到如何做測試組和探針組有關(其中規定有哪些要素共同與探頭):

SELECT 
    e.set_no AS [test set], 
    m.set_no AS [probe set], 
    e.elem [common element] 
FROM 
    @elements e 
JOIN 
    @multi_probe m ON e.elem = m.elem 

結果:

test set probe set common element 
----------- ----------- -------------- 
1   3   A 
1   1   B 
1   3   B 
1   1   C 
1   2   C 
1   3   C 
1   1   F 
1   2   F 
2   3   A 
2   1   B 
2   3   B 
2   1   C 
2   2   C 
2   3   C 
3   1   F 
3   2   F 
4   1   B 
4   3   B 
4   1   C 
4   2   C 
4   3   C 
4   1   F 
4   2   F 
5   1   F 
5   2   F 

(2)算多少共同每個測試組和探針集之間的元素(內部連接的意思是我們已經離開了「不匹配」除外)

SELECT 
    e.set_no AS [test set], 
    m.set_no AS [probe set], 
    COUNT(*) AS [common element count] 
FROM 
    @elements e 
    JOIN 
     @multi_probe m ON e.elem = m.elem 
GROUP BY 
    e.set_no, m.set_no 
ORDER BY 
    e.set_no, m.set_no 

結果:

test set probe set common element count 
----------- ----------- -------------------- 
1   1   3 
1   2   2 
1   3   3 
2   1   2 
2   2   1 
2   3   3 
3   1   1 
3   2   1 
4   1   3 
4   2   2 
4   3   2 
5   1   1 
5   2   1 

(3)把試驗組和探針在各行設置的計數(子查詢可能不是最優雅)

SELECT 
    e.set_no AS [test set], 
    m.set_no AS [probe set], 
    COUNT(*) AS [common element count], 
    (SELECT COUNT(*) FROM @elements e1 WHERE e1.set_no = e.set_no) AS [test set count], 
    (SELECT COUNT(*) FROM @multi_probe m1 WHERE m1.set_no = m.set_no) AS [probe set count] 
FROM 
    @elements e 
    JOIN @multi_probe m ON e.elem = m.elem 
GROUP BY 
    e.set_no, m.set_no 
ORDER BY 
    e.set_no, m.set_no 

結果:

test set probe set common element count test set count probe set count 
----------- ----------- -------------------- -------------- --------------- 
1   1   3     6    3 
1   2   2     6    2 
1   3   3     6    3 
2   1   2     3    3 
2   2   1     3    2 
2   3   3     3    3 
3   1   1     3    3 
3   2   1     3    2 
4   1   3     3    3 
4   2   2     3    2 
4   3   2     3    3 
5   1   1     1    3 
5   2   1     1    2 

(4)求解決方案:只保留那些具有相同元素數量的測試集合和探針集合,並且這個數量也是共同元素的數量,即測試集合和探針集合是相同的

SELECT 
    e.set_no AS [test set], 
    m.set_no AS [probe set] 
FROM 
    @elements e 
JOIN 
    @multi_probe m ON e.elem = m.elem 
GROUP BY 
    e.set_no, m.set_no 
HAVING 
    COUNT(*) = (SELECT COUNT(*) FROM @elements e1 WHERE e1.set_no = e.set_no) 
    AND (SELECT COUNT(*) FROM @elements e1 WHERE e1.set_no = e.set_no) = (SELECT COUNT(*) FROM @multi_probe m1 WHERE m1.set_no = m.set_no) 
ORDER BY 
    e.set_no, m.set_no 

結果:

test set probe set 
----------- ----------- 
2   3 
4   1 

藉口@!而非# S,我想表變量更好:)

+1

yah,re:'@',但是你的統計數字在哪裏,嗯? – 2010-09-08 00:55:37

+0

一個很大的區別是臨時表使用統計信息,表變量不需要。 – ErikE 2010-09-08 01:46:52

+0

標記爲已接受。我曾希望有一個不使用聚合的解決方案。事實證明,我對第一個問題的解決方案很容易擴展到多個探針。彙總版本的估計執行成本略低於非彙總版本的執行成本0.031與0.038。不知道它如何擴展到大量的數據。 – 2010-09-08 01:50:48

1

我可以提交問題(1)更多「數學上傾向」的解決方案,在SQL Server語法中:

SELECT 
    s.set_no 
FROM 
    #sets s 
    JOIN @elements e ON s.set_no = e.set_no 
    LEFT JOIN #probe p ON e.elem = p.elem 
GROUP BY 
    s.set_no 
HAVING 
    COUNT(DISTINCT p.elem) = COUNT(*) 
    AND COUNT(*) = (SELECT COUNT(*) FROM #probe) 
  • COUNT(*)將始終表示在各試驗組元素(由於LEFT JOIN
  • COUNT(DISTINCT p.elem)的數量將表示在測試組的元素,在一個元件之間的「匹配」的數目探針組(因爲NULL旨意不計算在內),即在設置探頭許多元素是如何也存在於測試裝置

翻譯成數學術語COUNT(DISTINCT p.elem) = COUNT(*)將表示所述測試組是潛艇et(),而COUNT(*) = (SELECT COUNT(*) FROM #probe)會表示測試集的基數等於探針集的基數(|test| = |probe|)。從這兩個條件我們得出結論test = probe

+0

我喜歡數學框架。如果我知道更多的數學,我會翻譯我自己的解決方案來設置符號,並顯示兩者如何相等(或不是,視情況而定)。 – 2010-09-07 23:14:02

+0

難道你不能將'left join'改爲'inner join',刪除'count(distinct p.elem)',並得到相同的結果嗎?或者至少用'count(elem)'替換'count(distinct elem)'? – 2010-09-07 23:14:34

+1

如果你使用'INNER'而不是'LEFT','SELECT'(在刪除GROUP和HAVING以查看實際行之後)只會選擇與元素匹配的那些元素在探針中。這隻會轉化爲知道這些集合具有探測中的所有元素,但可能還有其他元素。添加COUNT(*)=(SELECT COUNT(*)FROM #probe)條件只會保證結果集合是探測器的超集(例如set 1也可以作爲匹配)。 – CyberDude 2010-09-07 23:28:37

0

[回答我的問題....]

首先,該解決方案。在except語法可以處理多個列和空值正常,所以這是更接近通用的解決方案:

SELECT 
    s.set_no AS test_set_no 
, p.set_no AS probe_set_no 
FROM #test_sets s CROSS JOIN #probe_sets p 
WHERE NOT EXISTS (
    SELECT elem FROM #test_elements te WHERE te.set_no = s.set_no EXCEPT 
    SELECT elem FROM #probe_elements pe WHERE pe.set_no = p.set_no) 
    AND NOT EXISTS (
    SELECT elem FROM #probe_elements pe WHERE pe.set_no = p.set_no EXCEPT 
    SELECT elem FROM #test_elements te WHERE te.set_no = s.set_no) 
ORDER BY 
    test_set_no 
, probe_set_no 

接着,修改後的數據集:

IF OBJECT_ID('tempdb..#test_elements') IS NOT NULL DROP TABLE #test_elements 
IF OBJECT_ID('tempdb..#test_sets') IS NOT NULL DROP TABLE #test_sets 

CREATE TABLE #test_sets (set_no INT, PRIMARY KEY (set_no)) 
CREATE TABLE #test_elements (set_no INT, elem CHAR(1), PRIMARY KEY (set_no, elem)) 

INSERT #test_elements VALUES (1, 'A') 
INSERT #test_elements VALUES (1, 'B') 
INSERT #test_elements VALUES (1, 'C') 
INSERT #test_elements VALUES (1, 'D') 
INSERT #test_elements VALUES (1, 'E') 
INSERT #test_elements VALUES (1, 'F') 
INSERT #test_elements VALUES (2, 'A') 
INSERT #test_elements VALUES (2, 'B') 
INSERT #test_elements VALUES (2, 'C') 
INSERT #test_elements VALUES (3, 'D') 
INSERT #test_elements VALUES (3, 'E') 
INSERT #test_elements VALUES (3, 'F') 
INSERT #test_elements VALUES (4, 'B') 
INSERT #test_elements VALUES (4, 'C') 
INSERT #test_elements VALUES (4, 'F') 
INSERT #test_elements VALUES (5, 'F') 

INSERT #test_sets SELECT DISTINCT set_no FROM #test_elements 

IF OBJECT_ID('tempdb..#probe_elements') IS NOT NULL DROP TABLE #probe_elements 
IF OBJECT_ID('tempdb..#probe_sets') IS NOT NULL DROP TABLE #probe_sets 
CREATE TABLE #probe_sets (set_no INT PRIMARY KEY (set_no)) 
CREATE TABLE #probe_elements (set_no INT, elem CHAR(1) PRIMARY KEY (set_no, elem)) 

INSERT #probe_elements VALUES (1, 'B') 
INSERT #probe_elements VALUES (1, 'C') 
INSERT #probe_elements VALUES (1, 'F') 
INSERT #probe_elements VALUES (2, 'C') 
INSERT #probe_elements VALUES (2, 'F') 
INSERT #probe_elements VALUES (3, 'A') 
INSERT #probe_elements VALUES (3, 'B') 
INSERT #probe_elements VALUES (3, 'C') 

INSERT #probe_sets SELECT DISTINCT set_no FROM #probe_elements 

通過比較,使用聚集體,如每Cyber​​Dude :

SELECT 
    e.set_no AS [test set] 
, m.set_no AS [probe set] 
FROM #test_elements e 
JOIN #probe_elements m ON e.elem = m.elem 
GROUP BY 
    e.set_no 
, m.set_no 
HAVING (SELECT COUNT(*) FROM #test_elements e1 WHERE e1.set_no = e.set_no) 
    = (SELECT COUNT(*) FROM #probe_elements m1 WHERE m1.set_no = m.set_no) 
    AND (SELECT COUNT(*) FROM #test_elements e1 WHERE e1.set_no = e.set_no) 
    = COUNT(*) 
ORDER BY 
    e.set_no 
, m.set_no