2015-01-13 12 views
6

Tôi có một bảng các nhân viên chứa khoảng 25 cột. Ngay bây giờ có rất nhiều bản sao và tôi muốn thử và loại bỏ một số các bản sao này.Xóa các bản sao có ít giá trị null

Trước tiên, tôi muốn tìm các bản sao bằng cách tìm nhiều bản ghi có cùng giá trị trong tên, họ, số nhân viên, số công ty và trạng thái.

SELECT 
    firstname,lastname,employeenumber, companynumber, statusflag 
FROM 
    employeemaster 
GROUP BY 
    firstname,lastname,employeenumber,companynumber, statusflag 
HAVING 
    (COUNT(*) > 1) 

Điều này mang lại cho tôi bản sao nhưng mục tiêu của tôi là tìm và lưu giữ bản ghi tốt nhất và xóa các bản ghi khác. "Bản ghi đơn tốt nhất" được xác định bởi bản ghi với số lượng giá trị NULL ít nhất trong tất cả các cột khác. Tôi có thể làm cái này như thế nào?

Tôi đang sử dụng Microsoft SQL Server 2012 MGMT Studio.

VÍ DỤ:

enter image description here

đỏ: DELETE xanh: GIỮ

CHÚ Ý: Có rất nhiều các cột trong bảng so với những gì bảng này cho thấy.

+0

bạn có thể chỉnh sửa các hồ sơ mẫu câu hỏi và dự kiến ​​sản lượng –

+0

Chắc chắn, tôi đã thêm một ví dụ. – user3788671

+2

Một phương pháp rất thô lỗ nhưng bạn có thể tính tổng chiều dài của văn bản trong mỗi cột và sắp xếp theo đó không? Hoặc cộng một IsNull()? – Liath

Trả lời

2

Bạn có thể sử dụng bảng sys.columns để nhận danh sách các cột và tạo truy vấn động. Truy vấn này sẽ trả về giá trị 'KeepThese' cho mỗi bản ghi bạn muốn giữ dựa trên các tiêu chí đã cho của bạn.

-- insert test data 
create table EmployeeMaster 
    (
    Record int identity(1,1), 
    FirstName varchar(50), 
    LastName varchar(50), 
    EmployeeNumber int, 
    CompanyNumber int, 
    StatusFlag int, 
    UserName varchar(50), 
    Branch varchar(50) 
); 
insert into EmployeeMaster 
    (
    FirstName, 
    LastName, 
    EmployeeNumber, 
    CompanyNumber, 
    StatusFlag, 
    UserName, 
    Branch 
) 
    values 
    ('Jake','Jones',1234,1,1,'JJONES','PHX'), 
    ('Jake','Jones',1234,1,1,NULL,'PHX'), 
    ('Jake','Jones',1234,1,1,NULL,NULL), 
    ('Jane','Jones',5678,1,1,'JJONES2',NULL); 

-- get records with most non-null values with dynamic sys.column query 
declare @sql varchar(max) 
select @sql = ' 
    select e.*, 
     row_number() over(partition by 
          e.FirstName, 
          e.LastName, 
          e.EmployeeNumber, 
          e.CompanyNumber, 
          e.StatusFlag 
          order by n.NonNullCnt desc) as KeepThese 
    from EmployeeMaster e 
     cross apply (select count(n.value) as NonNullCnt from (select ' + 
      replace((
       select 'cast(' + c.name + ' as varchar(50)) as value union all select ' 
       from sys.columns c 
       where c.object_id = t.object_id 
       for xml path('') 
       ) + '#',' union all select #','') + ')n)n' 
from sys.tables t 
where t.name = 'EmployeeMaster' 

exec(@sql) 
+0

Tuyệt vời! :) Nhưng bạn có thể giải thích nó lọc 'count (n.value)' để chỉ lấy giá trị của cột không null không? Đầu tiên tôi nghĩ rằng nó được thực hiện bởi 'cross' áp dụng, nhưng nó dường như được thực hiện bằng cách' đếm' chỉ dùng 'không null' giá trị vào tài khoản. Tôi có đúng không? – pkuderov

+1

Có bạn là chính xác. Bất cứ khi nào bạn đếm một cột, nó chỉ đếm các giá trị không null: số đếm (giá trị) từ (chọn 1 làm giá trị công đoàn tất cả chọn null là giá trị) v –

1

Hãy thử điều này.

;WITH cte 
    AS (SELECT Row_number() 
        OVER(
        partition BY firstname, lastname, employeenumber, companynumber, statusflag 
        ORDER BY (SELECT NULL)) rn, 
       firstname, 
       lastname, 
       employeenumber, 
       companynumber, 
       statusflag, 
       username, 
       branch 
     FROM employeemaster), 
    cte1 
    AS (SELECT a.firstname, 
       a.lastname, 
       a.employeenumber, 
       a.companynumber, 
       a.statusflag, 
       Row_number() 
        OVER(
        partition BY a.firstname, a.lastname, a.employeenumber, a.companynumber, a.statusflag 
        ORDER BY (CASE WHEN a.username IS NULL THEN 1 ELSE 0 END +CASE WHEN a.branch IS NULL THEN 1 ELSE 0 END))rn 
         -- add the remaining columns in case statement 
     FROM cte a 
       JOIN employeemaster b 
        ON a.firstname = b.firstname 
        AND a.lastname = b.lastname 
        AND a.employeenumber = b.employeenumber 
        AND a.companynumbe = b.companynumber 
        AND a.statusflag = b.statusflag) 
SELECT * 
FROM cte1 
WHERE rn = 1 
1

Tôi thử nghiệm với MySQL và sử dụng NULL Chuỗi concat để tìm thấy bản ghi tốt nhất. Bởi vì LENGTH (NULL || 'dữ liệu') là 0. Chỉ khi tất cả các cột không NULL tồn tại một số chiều dài. Có lẽ đây không phải là perfekt.

create table EmployeeMaster 
    (
    Record int auto_increment, 
    FirstName varchar(50), 
    LastName varchar(50), 
    EmployeeNumber int, 
    CompanyNumber int, 
    StatusFlag int, 
    UserName varchar(50), 
    Branch varchar(50), 

    PRIMARY KEY(record) 
); 
INSERT INTO EmployeeMaster 
    (
    FirstName, LastName, EmployeeNumber, CompanyNumber, StatusFlag, UserName, Branch 
) VALUES ('Jake', 'Jones', 1234, 1, 1, 'JJONES', 'PHX'), ('Jake', 'Jones', 1234, 1, 1, NULL, 'PHX'), ('Jake', 'Jones', 1234, 1, 1, NULL, NULL), ('Jane', 'Jones', 5678, 1, 1, 'JJONES2', NULL); 

ý tưởng truy vấn của tôi trông như thế này

SELECT e.* 
    FROM employeemaster e 
    JOIN (SELECT firstname, 
       lastname, 
       employeenumber, 
       companynumber, 
       statusflag, 
       MAX(LENGTH (username || branch)) data_quality 
      FROM employeemaster 
     GROUP BY firstname, lastname, employeenumber, companynumber, statusflag 
     HAVING count(*) > 1 
     ) g 
    ON LENGTH (username || branch) = g.data_quality 
Các vấn đề liên quan