2016-09-08 37 views
13

Tôi đang cố gắng lấy số lượng giá trị trùng lặp trên hai cột nhóm trên một cột khác trong SQL Server.Riêng biệt của hai cột nhóm trên một cột khác

Dưới đây là một kịch bản mẫu mà tôi đang thực hiện.

DECLARE @mytable TABLE (CampName varchar(10),ID VARCHAR(10),ListName varchar(10)) 
    INSERT INTO @mytable 
      (CampName, ID, ListName) 
    VALUES ('A', 'X', 'Y'), ('A', 'X', 'Y'), 
      ('A', 'Y', 'Z'), ('A', 'Y', 'Z'), 
      ('A', 'Y', 'Z'), ('A', 'P', 'Q'), 
      ('B', 'X', 'Y'), ('B', 'X', 'Y'), 
      ('B', 'Y', 'Z'), ('B', 'Y', 'Z'), 
      ('B', 'Y', 'Z'), ('B', 'P', 'Q'), 
      ('B', 'R', 'S'), ('B', 'R', 'S') 

Điều này sẽ dẫn đến bảng sau.

CampName ID ListName 
------------------------------------- 
     A  X  Y 
     A  X  Y -- Duplicate Record 
     A  Y  Z 
     A  Y  Z -- Duplicate Record 
     A  Y  Z -- Duplicate Record 
     A  P  Q 
     B  X  Y 
     B  X  Y -- Duplicate Record 
     B  Y  Z 
     B  Y  Z -- Duplicate Record 
     B  Y  Z -- Duplicate Record 
     B  P  Q 
     B  R  S 
     B  R  S -- Duplicate Record 

tôi cần đầu ra như sau:

CampName dupcount 
------------------- 
A   3 
B   4 

Về cơ bản, tôi cần phải tìm ra các số trùng lặp (ID, listname) cho mỗi CampName không phụ thuộc vào những gì các giá trị nhân bản đang có.

Hãy cho tôi biết nếu tôi có thể làm rõ điều gì khác về vấn đề này. Bất kỳ trợ giúp nào sẽ được đánh giá cao.

Trả lời

5

Đây là một cách đơn giản để có được kết quả mong muốn:

select t.campname, count(*) - count(distinct t.listname) as num_duplicates 
from @mytable t 
group by t.campname; 

Logic là count(*) đếm tất cả các hàng. count(distinct) đếm số danh sách riêng biệt. Sự khác biệt là số lượng các bản sao.

CHỈNH SỬA:

Giorgios làm cho một điểm tốt. Tuy nhiên, dữ liệu trông giống như idname chứa cùng thông tin, do đó chỉ có một thông tin cần thiết. Nếu bạn phải sử dụng cả hai, nhiều cơ sở dữ liệu sẽ cho phép bạn làm:

select t.campname, count(*) - count(distinct t.id, t.listname) as num_duplicates 
from @mytable t 
group by t.campname; 

Nhưng không phải SQL Server. Thay vào đó, hãy ghép chúng lại với nhau:

select t.campname, 
     count(*) - count(distinct concat(t.id, ':', t.listname)) as num_duplicates 
from @mytable t 
group by t.campname; 
+1

Chỉ hoạt động nếu trường 'id' hoàn toàn dư thừa. Trong ví dụ dữ liệu dường như là trường hợp, nhưng trong từ ngữ 'số lượng trùng lặp (ID, ListName) cho mỗi CampName' nó xuất hiện mà nó không thừa ... – MatBailie

+2

Tôi nghĩ rằng' khác biệt' nên xem xét * cả hai * lĩnh vực, không chỉ 'listname'. –

4

Có một chút mơ hồ trong câu hỏi.

Nếu bạn tin rằng tất cả các IDListName bạn kết hợp luôn bằng nhau, các truy vấn dưới đây làm việc cho bạn:

Bạn chỉ có thể làm điều này bằng cách sử dụng DISTINCT bên trong của bạn COUNT

SELECT CampName, COUNT(DISTINCT ListName) UniqueCount 
FROM @mytable 
GROUP BY CampName 

Nếu bạn nghi ngờ , sự kết hợp có thể không bằng nhau mọi lúc, bạn cần cân nhắc tính kết hợp cả hai cột IDListName.

Giả định nhà điều hành ghép nối | sẽ không có mặt trong bất kỳ trong hai cột.

SELECT CampName, COUNT(DISTINCT ID+'|'+ListName) UniqueCount 
FROM @mytable 
GROUP BY CampName 

Nếu bạn lo lắng về đếm số lượng bản sao của hàng

SELECT CampName, COUNT(*) - COUNT(DISTINCT ID+'|'+ListName) dupCount 
FROM @mytable 
GROUP BY CampName 

Một thay thế, tôi nghĩ rằng

;WITH Temp AS 
(
    SELECT CampName, ID, ListName, COUNT(*) UniqueCount 
    FROM @mytable 
    GROUP BY CampName, ID, ListName 
) 
SELECT CampName, COUNT(UniqueCount) count 
FROM Temp 
GROUP BY CampName 
+0

DISTINCT không phải là một chức năng. I E. bạn có thể làm 'COUNT (DISTINCT ListName)'. – jarlh

+0

Bạn nói đúng nhưng không tạo ra lỗi nào :) – techspider

+0

Không, và bạn thậm chí có thể làm 'COUNT (DISTINCT ((((ListName)))))', nếu bạn muốn. – jarlh

9

Bạn có thể sử dụng các truy vấn sau đây:

SELECT CampName, SUM(cnt) AS dupcount 
FROM (
    SELECT CampName, COUNT(*) - 1 AS cnt 
    FROM @mytable 
    GROUP BY CampName, ID, ListName 
    HAVING COUNT(*) > 1) AS t 
GROUP BY CampName 

Truy vấn bên trong sử dụng mệnh đề HAVING để lọc ra các mục không trùng lặp. Nó cũng tính toán số lượng bản ghi trùng lặp cho mỗi ID, ListName. Truy vấn bên ngoài chỉ đơn giản là tổng số bản sao.

+0

Cả hai trường hợp mạnh nhất (không có trường hợp lỗi cạnh) và trình diễn (không ghép các trường cho phép sử dụng quét chỉ mục thay vì quét bảng, nếu chỉ mục thích hợp tồn tại), hãy trả lời tại đây ... – MatBailie

5

Tôi tin rằng số riêng biệt của sự kết hợp của IDListName cần phải được trừ vào tổng số cho mỗi CampName nhóm để có được kết quả chính xác.

SELECT t.CampName, 
     COUNT(*) - COUNT(DISTINCT 'ColOne' + ID + 'ColTwo' + ListName) AS dupcount 
FROM yourTable t 
GROUP BY CampName 

Truy vấn này sử dụng một thủ thuật, được concatenating IDListName cột, trong đó có cả văn bản, để tạo hiệu quả một pseudo-nhóm. Sự cần thiết cho điều này là DISTINCT chỉ hoạt động trên một cột duy nhất, nhưng bạn có hai cột cần được xem xét.

tham khảo:Quora: In SQL, how to I count DISTINCT over multiple columns?

+0

Kết nối là nguy hiểm; ''X' + 'XY' == 'XX' + 'Y'' Ngay cả khi thêm dấu phân cách là không đủ; ''X' + ',' + ', Y' == 'X,' + ',' + 'Y''. Để được mạnh mẽ sẽ yêu cầu một tìm kiếm và thay thế để 'thoát' bất kỳ sự xuất hiện của bất kỳ dấu phân cách được sử dụng. – MatBailie

+0

@MatBailie Chúng tôi cũng có thể thêm một số nhận dạng cho mỗi cột mà chúng tôi mong đợi là duy nhất (ví dụ: 'ColOne' cho cột đầu tiên,' ColTwo' cho cột thứ hai). Sau đó, ví dụ của bạn sẽ trở thành 'ColOneX + ColTwoXY! = ColOneXX + ColTwoY' –

+0

Thực tế điều này là không thể, nhưng nó vẫn không mạnh mẽ 100%; ' 'ColOne' + '12' + 'ColTwo' + 'XXColTwoXX' == 'ColOne' + '12ColTwoXX' + 'ColTwo' + 'XX'' – MatBailie

2

Hãy thử một cái gì đó như thế này, phân tích câu lệnh SELECT, mệnh đề WITH không phải là quan trọng đối với logic:

WITH input_data AS (
    SELECT 'X' AS x, 'Y' AS y FROM DUAL 
    UNION ALL 
    SELECT 'X' AS x, 'Y' AS y FROM DUAL 
    UNION ALL 
    SELECT 'X' AS x, 'A' AS y FROM DUAL 
) 
SELECT input_data.*, COUNT(*) OVER (PARTITION BY x, y) - 1 AS numer_duplicates 
FROM input_data 
; 
+0

Cần một kết quả độc lập cho mỗi Tên miền. Bởi thời gian bạn đối phó với điều đó bạn kết thúc với câu trả lời lồng nhau được cung cấp bởi GiorgosBetsos. – MatBailie

+0

@MatBailie yup, chỉ cần sử dụng chức năng phân tích làm giải pháp thay thế. – dood

+0

Quan điểm của tôi là giải pháp thay thế này không làm những gì mà OP yêu cầu. OP yêu cầu số lượng bản sao * Mỗi tên miền *. – MatBailie

3

Bạn cũng có thể lấy kết quả tương tự với CONCAT nó là đáng tin cậy hơn

SELECT CampName, 
    COUNT(ListName)-COUNT(DISTINCT CONCAT(id,ListName)) tot 
FROM #tmp 
GROUP BY CampName 
Các vấn đề liên quan