2010-06-12 37 views
5

Tôi có một bảng với:SQL Đếm đồ vật độc đáo được xác định bởi các thông số

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

Đó đại diện cho đối tượng được xác định với các giá trị như:

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

Tôi muốn đếm số lượng các đối tượng với các thông số khác nhau bằng cách sử dụng truy vấn SQL, vì vậy trong trường hợp này, nó sẽ là 2 đối tượng duy nhất là 1 và 3 có cùng tham số.

Không có ràng buộc về số lượng tham số, có thể là 0 hoặc bất kỳ số nào khác.

Cơ sở dữ liệu là Microsoft SQL Server 2000. Nhưng tôi không ngại khi biết giải pháp cho các cơ sở dữ liệu khác.

+0

Làm thế nào để bạn đại diện zero thông số? Một NULL trong cột 'parameters' và một ràng buộc hoặc trigger để ngăn chặn bất kỳ phi NULL nào với cùng một' id'? – pilcrow

+0

@pilcrow: Chắc chắn, có một bảng khác với id đối tượng làm khóa chính. – Eduardo

Trả lời

0

Bạn có thể sử dụng một điều khoản having để lọc cho hai tham số duy nhất:

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

Tôi đã chỉnh sửa nhiệm vụ để làm rõ rằng: Không có ràng buộc về số lượng tham số có thể là 0 hoặc bất kỳ số nào khác. – Eduardo

3

Nếu tôi hiểu đúng, bạn muốn số lượng biệt kết hợp của parameter s mỗi id đại diện trong bảng của bạn, có thể với số lượng thực thể trưng bày từng kết hợp riêng biệt.

tôi không thể nói cho SQL Server, nhưng dưới MySQL bạn có thể làm một cái gì đó như thế này:

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; 

mà sẽ cung cấp cho bạn điều này:

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 sẽ cung cấp cho bạn số lượng các tập tham số riêng biệt.

+0

Có, điều này sẽ làm việc cho MySQL nhưng tôi cần giải pháp cho Microsoft SQL Server 2000 – Eduardo

+0

Nếu có thể, tôi khuyên bạn nên thực hiện chức năng nối nhóm của riêng bạn (http://sqlblog.com/blogs/adam_machanic/archive/2006 /07/12/rowset-string-concatenation-which-method-is-best.aspx, ví dụ, mặc dù tìm kiếm "nối nối hàng" sẽ mang lại cho người khác). Tôi nghĩ giải pháp này rất đơn giản và trực quan. –

+0

Điều này có thể không hoạt động như mong muốn OP. Ông nói rằng một ID có thể có các tham số bằng không - thường có nghĩa là một giá trị null hoặc trực tiếp trong bảng hoặc trong một phép nối trái. Nhưng 'GROUP_CONCAT' bỏ qua các giá trị rỗng. Nó sẽ cho kết quả không hợp lệ. (Tôi nói "nên" verus "sẽ" chỉ vì tôi không có một máy chủ MySQL tiện dụng vào lúc này, để xác minh). –

2

OK, đây là nỗ lực của tôi. Có thể thực hiện logic này theo cách không yêu cầu 5 truy cập vào cùng một bảng, nhưng tôi không thể nghĩ ra nó ngay bây giờ.

Logic ở đây trước hết là loại bỏ các đối tượng trùng lặp, sau đó đếm số ID còn lại. Truy vấn con NOT IN đại diện cho các đối tượng có đối tượng phù hợp với ID nhỏ hơn. Truy vấn con tham gia các tham số của hai đối tượng t1 và t2, sau đó đếm số lượng tham số phù hợp với mỗi cặp t1/t2. Nếu số tham số phù hợp giống với số tham số trong t1 và t2, thì t2 và t1 là các kết quả phù hợp và chúng ta nên loại trừ t1 khỏi resultset.

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) 
     ); 

Kết quả trên SQL Server 2008 R2:

num_groups 
3 

Đối với đối tượng với 0 thông số, nó phụ thuộc vào cách chúng được lưu trữ, nhưng nói chung, bạn muốn chỉ cần thêm một đến trả lời ở trên nếu có bất kỳ đối tượng nào có tham số 0.

+0

Thực ra điều này không hiệu quả. Nó sẽ cung cấp cho các giá trị không chính xác nếu nhiều hơn một ID có tham số bằng không. –

1

Không có cách nào dễ dàng để thực hiện điều này trong SQL Server 2000, với các điều kiện được chỉ định, nhưng sau đây sẽ làm việc trong hầu hết các trường hợp và cảnh báo bạn nếu nó không hoạt động.

bảng Given, "tbl":

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

.
Tạo chức năng này:

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 

.
Sau đó truy vấn này:

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 

.
Sẽ cung cấp những gì bạn yêu cầu.
Kết quả:

NumIDs NumParams ParamList 
    2   2   A, B 
    1   2   C, D 
    1   1   *null*, A 
    1   1   A 
    1   0   *null* 
Các vấn đề liên quan