2010-06-28 15 views
5

Tôi có tập dữ liệu giống như sau.Chọn chính xác một hàng cho mỗi nhân viên sử dụng trường không theo thứ tự làm tiêu chí

EMPLID PHONE_TYPE PHONE 
------ ---------- -------- 
100  HOME  111-1111 
100  WORK  222-2222 
101  HOME  333-3333 
102  WORK  444-4444 
103  OTHER  555-5555 

Tôi muốn chọn chính xác một hàng cho từng nhân viên sử dụng trường PHONE_TYPE để thiết lập tùy chọn. Tôi muốn số điện thoại HOME nếu nhân viên có số như trường hợp cho nhân viên 100 và 101. Nếu số HOME không có, tôi muốn số WORK (nhân viên 102), và như một phương sách cuối cùng tôi sẽ dùng số như với nhân viên 103. Trong thực tế, bảng của tôi có khoảng một chục giá trị cho trường PHONE_TYPE, vì vậy tôi cần có khả năng mở rộng bất kỳ giải pháp nào để bao gồm nhiều hơn ba giá trị mà tôi đã hiển thị trong ví dụ. Có suy nghĩ gì không? Cảm ơn.

+0

Vì vậy, bạn muốn có một bản ghi cho mỗi ID nhân viên, với tùy chọn cho bản ghi dựa trên loại điện thoại? –

+0

Điều đó là chính xác.Bảng này không đảm bảo có một điện thoại HOME cho mỗi nhân viên, nhưng tôi cần phải chọn một cái gì đó và tôi không muốn sử dụng một TOP đơn giản (1) để có được một giá trị ngẫu nhiên. Về cơ bản, tôi muốn có lựa chọn thứ 2, lựa chọn thứ 3, v.v. – SteveM82

+1

Bạn có tất cả các loại điện thoại được lưu trữ trong bảng tra cứu, với cột hiển thị thứ tự ưa thích của bạn không? –

Trả lời

2

Tôi quên, Server 2000 có hỗ trợ Coalesce không? Nếu có, tôi nghĩ điều này sẽ hoạt động:

Select Distinct EmplID, Coalesce(
    (Select Phone from Employees where emplid = e1.emplid and phone_type = 'HOME'), 
    (Select Phone from Employees where emplid = e1.emplid and phone_type = 'WORK'), 
    (Select Phone from Employees where emplid = e1.emplid and phone_type = 'OTHER') 
) as Phone 
From Employees e1 
+0

Đáng ngạc nhiên là có, SQL Server 2000 hỗ trợ Coalesce. Tôi tin rằng điều này sẽ hoạt động, mặc dù mã sẽ cần phải được chỉnh sửa nếu các giá trị PHONE_TYPE mới được thêm vào (không, nhưng có thể). Cảm ơn. – SteveM82

+0

Bạn hoàn toàn đúng. Cách tiếp cận trong câu trả lời khác sử dụng một bảng phụ sẽ yêu cầu giống nhau - bạn phải thêm các mục vào bảng phụ trợ của mình nếu bạn đã thêm một loại điện thoại mới. Cách tiếp cận nào tốt hơn tùy thuộc vào việc bạn có thể thêm các bảng phụ hay không. –

+0

Cách tiếp cận này yêu cầu thay đổi mã chương trình khi thêm loại điện thoại mới hoặc thay đổi mức độ ưu tiên tương đối. Giải pháp khác chỉ yêu cầu chỉnh sửa dữ liệu. Trường hợp ngoại lệ là nếu bạn đóng gói giải pháp này trong chế độ xem. Tuy nhiên, bạn có biết liệu SQL Server sẽ ngừng đánh giá các SELECT ngay sau khi nó gặp phải một kết quả trả về? Hoặc là tất cả các đánh giá SELECT, và sau đó COALESCE được thực hiện? –

3

Bạn cần thêm bảng phone_types (Phone_Type TEXT (Dù), INTEGER ưu tiên). Trong bảng này, liệt kê từng giá trị Phone_Type một lần và chỉ định mức ưu tiên cho nó (trong ví dụ của bạn, HOME sẽ là 1, WORK 2, OTHER 3, v.v.).

Sau đó, tạo chế độ xem tham gia cột Ưu tiên từ Phone_Types đến bảng Phone_Numbers của bạn (tưởng tượng chúng tôi gọi nó là Phone_Numbers_Ex).

Bây giờ, bạn có nhiều lựa chọn cho cách để có được kỷ lục từ Phone_Numbers_Ex với MIN (ưu tiên) cho một emplID nhất định, trong đó có lẽ là rõ ràng nhất là:

SELECT * FROM Phone_Numbers_Ex P1 WHERE NOT EXISTS 
    (SELECT * FROM Phone_Numbers_Ex P2 WHERE P2.EmplID = P1.EmplID AND P2.Priority < P1.Priority) 

Một cách khác là để tuyên bố quan điểm khác, hoặc truy vấn bên trong, dọc theo các dòng SELECT EmplID, MIN(Priority) AS Priority FROM Phone_Numbers_Ex GROUP BY EmplID và sau đó tham gia trở lại Phone_Numbers_Ex này trên cả EmplID và Priority.

+0

Larry, cảm ơn ý kiến ​​của bạn. Giải pháp mà g.d.d.c cung cấp đang hoạt động tốt vì các giá trị PHONE_TYPE của tôi có thể không thay đổi. Tôi đồng ý rằng chèn một hàng vào một bảng vì giải pháp của bạn tốt hơn là sửa đổi mã nếu các giá trị PHONE_TYPE có nhiều khả năng thay đổi hơn. Thêm vào đó, tôi đã học về một hàm mới - kết hợp lại. – SteveM82

0

Yêu cầu của bạn có thể không đầy đủ nếu nhân viên được phép có nhiều số điện thoại cho một loại điện thoại nhất định. Tôi đã thêm một phone_number_id chỉ để làm cho mọi thứ duy nhất và giả định rằng bạn sẽ muốn id thấp nhất nếu người đó có hai điện thoại cùng loại. Đó là khá tùy ý, nhưng bạn có thể thay thế nó bằng logic kinh doanh của riêng bạn.

Tôi cũng đã giả định một số loại bảng Phone_Types bao gồm mức độ ưu tiên của bạn cho số điện thoại nào sẽ được sử dụng. Nếu bạn chưa có bảng này, có lẽ bạn nên thêm nó. Nếu không có gì khác, nó cho phép bạn hạn chế các loại điện thoại bằng khóa ngoài.

SELECT 
    PN1.employee_id, 
    PN1.phone_type, 
    PN1.phone_number 
FROM 
    Phone_Numbers PN1 
INNER JOIN Phone_Types PT1 ON 
    PT1.phone_type = PN1.phone_type 
WHERE 
    NOT EXISTS 
    (
     SELECT * 
     FROM 
      Phone_Numbers PN2 
     INNER JOIN Phone_Types PT2 ON 
      PT2.phone_type = PN2.phone_type AND 
      (
       (PT2.priority < PT1.priority) 
--OR (PT2.priority = PT1.priority AND PN2.phone_number_id > PN1.phone_number_id) 
      ) 
    ) 

Bạn cũng có thể thực hiện điều này bằng LEFT JOIN thay vì KHÔNG tồn tại hoặc bạn có thể sử dụng TOP nếu bạn đang tìm số điện thoại cho một nhân viên. Chỉ cần thực hiện ĐẶT HÀNG HÀNG ĐẦU 1 theo thứ tự ưu tiên, phone_number_id.

Cuối cùng, nếu bạn chuyển sang SQL 2005 hoặc SQL 2008, bạn có thể sử dụng CTE với ROWNUMBER() OVER (ưu tiên ORDER BY, phone_number, PARTITION BY employee_id) < - Tôi nghĩ cú pháp của tôi có thể hơi bị tắt với dấu ngoặc đơn trên đó, nhưng hy vọng nó đủ rõ ràng. Điều đó sẽ cho phép bạn nhận được thông tin hàng đầu cho tất cả nhân viên bằng cách kiểm tra ROWNUMBER() = 1.

+0

Trường PHONE_TYPE là một khóa trong bảng của ứng dụng của tôi, vì vậy không thể có nhiều số điện thoại cho một loại nhất định. Cảm ơn. – SteveM82

+0

Điều đó làm cho nó dễ dàng hơn một chút. Tôi sẽ bình luận ra mã không cần thiết, nhưng vẫn để nó ở đó để tham khảo của người khác. –

0

Câu trả lời của g.d.d.c sử dụng truy vấn trong mệnh đề Chọn bạn có thể sử dụng các kết nối trái. Bạn có thể nhận được sự hoàn hảo tốt hơn, nhưng bạn nên kiểm tra tất nhiên.

SELECT 
    e1.iD, 
    Coalesce(phoneHome.Phone,phoneWork.Phone,phoneOther) phone 
FROm 
    employees e1 
    LEFT JOIN phone phoneHome 
    ON e1.emplId = phoneHome 
     and phone_type = 'HOME' 
    LEFT JOIN phone phoneWork 
    ON e1.emplId = phoneWork 
     and phone_type = 'WORK' 
    LEFT JOIN phone phoneWork 
    ON e1.emplId = phoneOTHER 
     and phone_type = 'OTHER' 
Các vấn đề liên quan