2010-03-02 44 views
6

Tôi đã có mã tương tự như sau trong một thủ tục được lưu trữ chèn một hàng vào một bảng, tôi muốn đặt cột cuối cùng (FieldD) thành @prmSomeValue trừ khi nó là null, nếu không chỉ sử dụng giá trị mặc định được xác định cho cột đó.Có cách nào để có điều kiện sử dụng giá trị cột mặc định trong câu lệnh INSERT..SELECT không?

IF (@prmSomeValue IS NULL) 
    INSERT INTO MyTable (fieldA,FieldB,FieldC) 
     SELECT A,B,C 
     FROM MyOtherTable 
ELSE 
    INSERT INTO MyTable (fieldA,FieldB,FieldC,FieldD) 
     SELECT A,B,C,@prmSomeValue 
     FROM MyOtherTable 

Tác phẩm này, nhưng vi phạm nguyên tắc DRY. Tôi đang cố gắng tìm một số cách để làm điều này với một tuyên bố chèn đơn. Một cái gì đó dọc theo dòng của mã giả sau đây.

INSERT INTO MyTable (fieldA,FieldB,FieldC,FieldD) 
     SELECT A,B,C,ISNULL(@prmSomeValue,DEFAULT) 
     FROM MyOtherTable 

Bất kỳ ai có ý tưởng?

Cập nhật - Một bước nữa
Ràng buộc mặc định không phải là giá trị bằng chữ, nhưng có chức năng như được hiển thị bên dưới.

...DEFAULT (suser_sname()) FOR [FieldD] 

Cập nhật
Cuối cùng tôi punted và chọn ít tệ nạn và chỉ cần sao chép hàm giá trị mặc định vào truy vấn của tôi thay vì rơi xuống thông qua các cấu hình mặc định cho cột. Tôi không thích nó, nhưng nó được thực hiện công việc với sự lặp lại ít hơn trong truy vấn của tôi.

INSERT INTO MyTable (fieldA,FieldB,FieldC,FieldD) 
     SELECT A,B,C,ISNULL(@prmSomeValue,suser_sname()) 
     FROM MyOtherTable 

Trả lời

3

Kể từ khi về cơ bản đây là những gì SQL Server đang làm, bạn có thể làm một cái gì đó như thế này để ít nhất tránh hai báo cáo gần giống (pseudo-code):

INSERT (columnA,B,C) ... ; 

IF @prmSomeValue IS NOT NULL 
    UPDATE ... ; 

Tôi không nghĩ rằng có cách COALESCE với giá trị mặc định.

+0

Ý tưởng thú vị. Không chắc chắn nếu nó là thích hợp hơn, nhưng chắc chắn giá trị một cuộc bỏ phiếu. – JohnFx

+0

Cảm ơn JohnFx, tôi nghĩ rằng nó có thể là thích hợp hơn khi có nhiều hơn một cột tùy chọn được xử lý theo cách này. Sau đó, bạn có thể nói "IF @foo IS NOT NULL HOẶC @bar IS NOT NULL, CẬP NHẬT SET foo = COALESCE (@foo, foo), bar = COALESCE (@bar, bar) WHERE" vv, thay vì viết câu lệnh chèn cho mọi kết hợp có thể. –

+0

Sử dụng ISNULL thay vì COALESCE, COALESCE dành cho nhiều đối số. Tôi sẽ không đi theo các phương thức field = parameter/field, nó sẽ giết hiệu năng SQL, làm cho việc tối ưu hóa các truy vấn và sử dụng các chỉ mục khó khăn hơn. Một câu lệnh if đơn giản sẽ hiệu quả hơn nhiều. – Zyphrax

0

này sức làm việc, phụ thuộc vào nếu bạn có nghĩa là giá trị mặc định được định nghĩa trong một hạn chế mặc định, hoặc trong mã? Nếu "ràng buộc" nó không thành công, nếu "mã" nó hoạt động. Chỉnh sửa: nghĩa là hạn chế. doh!

SELECT A,B,C,@prmSomeValue 
     FROM MyOtherTable 
     WHERE @prmSomeValue IS NOT NULL 
UNION ALL 
SELECT A,B,C,DEFAULT 
     FROM MyOtherTable 
     WHERE @prmSomeValue IS NULL 

Cách nào bạn muốn thực hiện, chỉ định cột trong mệnh đề INSERT yêu cầu giá trị.

Vì vậy, giải pháp đầu tiên của bạn là những gì bạn đã làm ...

+0

tôi đồng nghĩa với việc hạn chế mặc định được xác định cho các cột. Giống như nửa đầu của câu lệnh IF của tôi sẽ làm. Vì vậy, điều này sẽ không hoạt động. Lưu ý: Không bắt buộc phải chỉ định cột trong mệnh đề INSERT. Tôi có thể dựa vào thứ tự cột nếu nó là cần thiết để thực hiện công việc này, mặc dù tôi không muốn. – JohnFx

+0

JohnFx, nếu bạn rời khỏi danh sách cột, bạn sẽ cần có lựa chọn tiếp theo có cùng số cột khớp với bảng, nếu không bạn sẽ nhận được: "Msg 213, Cấp 16, Tiểu bang 1, Dòng 1 Tên cột hoặc số giá trị được cung cấp không khớp với định nghĩa bảng. " Ngay cả khi điều này đã làm việc, tôi sẽ ăn cắp rất thận trọng về việc dựa vào thứ tự cột (bản năng của bạn là đúng, IMHO). –

2

Tôi sẽ nói phương pháp của bạn là tốt. Một kiểm tra đơn giản theo sau bởi một chèn. Nếu bạn lo lắng về DRY, hãy đóng gói cuộc gọi để nó được gọi liên tục.

Tôi có thể nói rằng chèn/cập nhật trên db có thể tốn kém trên một số bảng (phụ thuộc vào mục tiêu thiết kế) vì vậy nếu bạn phải viết thêm mã để xử lý trường hợp này thì tôi thấy không có vấn đề gì với việc giao dịch.

+0

+1, bạn nên thử và ngăn chặn các khối mã trùng lặp. Tuy nhiên nhiều lập trình viên đang cố gắng thực hiện các nguyên tắc và thực hành mã hóa OO của họ cho T-SQL. Thường dẫn đến các truy vấn đẹp nhưng không hiệu quả. Đôi khi thật tuyệt vời khi thực hiện viết 5 truy vấn tương tự thay vì 1 truy vấn bán động - Giữ mã của bạn như cũ, nó được tập trung trong một thủ tục được lưu trữ, dễ bảo trì. – Zyphrax

+0

Bạn không biết rằng họ đánh bại những thứ đó vào đầu của chúng tôi đến điểm mà nó đau đớn về mặt thực tế có thực tế cùng một mã trùng lặp trên một trong hai kết thúc của một điều kiện? =) Bạn có thể là đúng mặc dù, có lẽ tôi đang suy nghĩ quá mức. – JohnFx

+1

Khi bạn chỉ có A hoặc B, thì tôi đồng ý rằng nó có thể vẫn ổn. Nhưng điều gì sẽ xảy ra khi bạn có bốn cột như vậy? Số lượng các câu lệnh INSERT có thể bạn cần dựa trên các tham số nào là NULL rất nhanh chóng phát nổ. Đôi khi bạn phải cân bằng hiệu quả và bảo trì. –

0

Something như thế này có thể làm việc (tho không phải là rất khá):

INSERT INTO MyTable (fieldA,FieldB,FieldC,FieldD) 
SELECT A,B,C, 
    case when @prmSomeValue is null 
then 
     (SELECT text FROM syscomments WHERE id IN (SELECT cdefault FROM syscolumns 
      WHERE id = object_id('MyTable') AND cdefault > 0)) 
    else @prmSomeValue 
    end 
FROM MyOtherTable 
+2

Điều gì sẽ xảy ra nếu giá trị mặc định thực sự là một công thức (chẳng hạn như GETDATE() hoặc NEWID())? nó sẽ được hiểu là một chuỗi, dẫn đến một lỗi hoặc dữ liệu không chính xác, tùy thuộc vào kiểu dữ liệu của cột. Ngoài ra bạn không muốn chắc chắn rằng bạn nhận được cột bên phải (có thể có nhiều hơn một cột nơi cdefault> 0, dẫn đến Msg 512 - truy vấn con trả lại nhiều hơn một giá trị)? Đối với SQL Server 2008, bạn có nên sử dụng các khung nhìn danh mục thay vì các bảng hệ thống không được chấp nhận không? –

+0

Tôi đã suy nghĩ về một cách tiếp cận tương tự, nhưng có một chút lo ngại về tác dụng phụ hoặc các vấn đề quyền liên quan đến việc sử dụng các bảng hệ thống như thế này, nhưng tôi cho rằng nó cảm thấy đủ vững chắc. Bất kỳ lời khuyên nào để cung cấp về kỹ thuật này? – JohnFx

+0

Doh! Một vấn đề lớn với cách tiếp cận này. Nếu mặc định là một hàm, nó chỉ chèn tên hàm, trong trường hợp của tôi là "getdate()". Rất cố gắng nhưng. – JohnFx

Các vấn đề liên quan