2010-06-12 91 views
5

我有一個表:SQL計數唯一對象

id | parameter 
1 | A 
1 | B 
2 | A 
3 | A 
3 | B 

代表的價值觀定義爲對象:

1 -> A,B 
2 -> A 
3 -> A,B 

我要計數的對象有不同的參數個數使用SQL查詢,因此在這種情況下,它將是2個唯一的對象,因爲1和3具有相同的參數。

參數個數沒有限制,可以有0個,也可以是其他任何數字。

該數據庫是Microsoft SQL Server 2000.但我不介意知道其他數據庫的解決方案。

+0

你怎麼代表零個參數? 'parameters'列中的NULL以及一個約束或觸發器,以防止對於相同'id'的任何非NULL值? – pilcrow 2010-06-15 16:40:37

+0

@pilcrow:當然,還有另一個表的對象ID作爲主鍵。 – Eduardo 2010-06-22 22:00:32

回答

0

您可以使用having子句來過濾兩個獨特的參數:

select count(*) 
from YourTable 
group by 
     id 
having count(distinct parameter) > 1 
+0

我編輯了這個任務來澄清:沒有限制參數的數量可以是0或任何其他數字。 – Eduardo 2010-06-12 05:15:19

3

如果我理解正確的話,你想在表中表示的每idparameter小號不同組合的數目,可能與展示每種不同組合的實體的數量。

我不能爲SQL Server說話,但在MySQL下,你可以做這樣的事情:

SELECT parameter_set, COUNT(*) AS entity_count 
    FROM (
      -- Here we "flatten" the different parameter combinations per id 
      SELECT id, 
        GROUP_CONCAT(parameter ORDER BY parameter) AS parameter_set 
       FROM tbl 
      GROUP BY id 
     ) d 
GROUP BY parameter_set; 

,這將給你:

parameter_set | entity_count 
---------------+-------------- 
A,B   |   2 -- two entities have params A, B 
A    |   1 -- one entity has param A 

SELECT COUNT(DISTINCT parameter_set FROM (... flattening query ...)) d會給你多少不同的參數集。

+0

是的,這將適用於MySQL,但我需要Microsoft SQL Server 2000的解決方案 – Eduardo 2010-06-12 05:16:58

+0

如果可能,我建議實現您自己的組連接功能(http://sqlblog.com/blogs/adam_machanic/archive/2006例如,/ 07/12/12/rowset-string-concatenation-which-method-is-best.aspx,儘管搜索「行連接」會產生其他)。我認爲這個解決方案簡單直觀。 – 2010-06-12 08:30:11

+0

這可能不符合OP的要求。他說ID可以有零個參數 - 通常表示直接在表中或左連接中的空值。但'GROUP_CONCAT'忽略空值。它應該給出一個無效的結果。 (我說「應該」verus「將」只是因爲我目前沒有MySQL服務器方便,來驗證)。 – 2010-06-15 03:53:52

2

好吧,這是我的嘗試。以不需要對同一個表進行5次訪問的方式實現此邏輯可能是可能的,但我現在無法想到它。

這裏的邏輯是首先消除重複的對象,然後計算剩餘的ID。 NOT IN子查詢表示具有較小ID的匹配對象的對象。子查詢連接兩個對象t1和t2的參數,然後計算每個t1/t2對匹配多少個參數。如果匹配參數的數量與t1中和t2中的參數數量相同,則t2和t1匹配,我們應該從結果集中排除t1。

DECLARE @tab TABLE (ID int, parameter varchar(2)); 

INSERT INTO @tab 
SELECT 1, 'A' UNION ALL 
SELECT 1, 'B' UNION ALL 
SELECT 2, 'A' UNION ALL 
SELECT 3, 'A' UNION ALL 
SELECT 3, 'B' UNION ALL 
SELECT 4, 'A' UNION ALL 
SELECT 5, 'C' UNION ALL 
SELECT 5, 'D'; 

SELECT 
    COUNT(DISTINCT t.ID) AS num_groups 
FROM 
    @tab AS t 
WHERE 
    t.ID NOT IN 
     (SELECT 
      t1.ID AS ID1 
     FROM 
       @tab AS t1 
      INNER JOIN 
       @tab AS t2 
      ON 
       t1.ID > t2.ID AND 
       t1.parameter = t2.parameter 
     GROUP BY 
      t1.ID, 
      t2.ID 
     HAVING 
      COUNT(*) = (SELECT COUNT(*) FROM @tab AS dupe WHERE dupe.ID = t1.ID) AND 
      COUNT(*) = (SELECT COUNT(*) FROM @tab AS dupe WHERE dupe.ID = t2.ID) 
     ); 

結果上的SQL Server 2008 R2:

num_groups 
3 

對於0參數的對象,這取決於他們是如何存儲,但通常,你只需要添加一個到如果有任何有0個參數的對象,請回答上面的問題

+0

其實這是行不通的。如果多個ID具有零參數,它將給出不正確的值。 – 2010-06-15 01:09:54

1

在指定條件下,在SQL Server 2000中沒有萬無一失的方法來執行此操作,但以下方法適用於大多數情況,它會在您無法正常工作時發出警告。

給定的表, 「TBL」:

ID Parameter 
1  A 
1  B 
2  A 
3  A 
3  B 
4  A 
4  NULL 
5  C 
5  D 
6  NULL 


創建此功能:

CREATE FUNCTION MakeParameterListFor_tblID (@ID INT) 
RETURNS VARCHAR(8000) 
AS 
BEGIN 
    DECLARE 
     @ParameterList VARCHAR(8000), 
     @ListLen  INT 
    SET 
     @ParameterList = '' 

    SELECT 
     @ParameterList = @ParameterList + COALESCE (Parameter, '*null*') + ', ' 
    FROM 
     tbl 
    WHERE 
     ID = @ID 
    ORDER BY 
     Parameter 


    SET @ListLen  = LEN (@ParameterList) 
    IF @ListLen > 7800 -- 7800 is a SWAG. 
     SET @ParameterList = '*Caution: overflow!*' + @ParameterList 
    ELSE 
     SET @ParameterList = LEFT (@ParameterList, @ListLen-1) -- Kill trailing comma. 

    RETURN @ParameterList 
END 
GO 


那麼這個查詢:

SELECT 
    COUNT (ID) AS NumIDs, 
    NumParams, 
    ParamList 
FROM 
    (
     SELECT 
      ID, 
      COUNT (Parameter)     AS NumParams, 
      dbo.MakeParameterListFor_tblID (ID) AS ParamList 
     FROM 
      tbl 
     GROUP BY 
      ID 
    ) AS ParamsByID 
GROUP BY 
    ParamsByID.ParamList, 
    ParamsByID.NumParams 
ORDER BY 
    NumIDs  DESC, 
    NumParams DESC, 
    ParamList ASC 


將提供你所要求的。
結果:

NumIDs NumParams ParamList 
    2   2   A, B 
    1   2   C, D 
    1   1   *null*, A 
    1   1   A 
    1   0   *null*