SQL Server có hỗ trợ TUYỆT VỜI và HẤP DẪN nhất không, nếu không thì cách giải quyết chung là gì?


15

Xem lại câu hỏi này có vẻ như đó là rất nhiều công việc không cần thiết. Họ đang cố gắng mở rộng một phạm vi với một ngày. Trong các cơ sở dữ liệu khác, bạn sẽ chỉ sử dụng greatestleast..

least(extendDate,min), greatest(extendDate,max)

Khi tôi cố gắng sử dụng những thứ này, tôi nhận được

'least' is not a recognized built-in function name.
'greatest' is not a recognized built-in function name.

Điều đó sẽ bao gồm mở rộng theo một trong hai hướng.

Đối với mục đích của câu hỏi, bạn vẫn sẽ phải thay thế phạm vi độc quyền.

Tôi chỉ tự hỏi làm thế nào người dùng SQL Server triển khai các mẫu truy vấn để bắt chước leastgreatestchức năng.

Bạn có hủy đăng ký các điều kiện thành các CASEbáo cáo hoặc có tiện ích mở rộng, tiện ích bổ sung của bên thứ ba hoặc giấy phép từ Microsoft cho phép chức năng này không?


Thật đáng kinh ngạc khi MSSQL không có triển khai cho LEAST/ GREATESTchức năng - gần như tất cả các đối thủ RDBMS có ít nhất tương đương. Ngoại lệ duy nhất tôi có thể tìm thấy là Sybase, nhưng điều đó cũng đã bị ngưng trong nhiều năm tại thời điểm này.
bẻ khóa

1
feedback.azure.com/forums/908035-sql-server/suggestions/, nếu bạn muốn bỏ phiếu cho điều này
Jangu

Câu trả lời:


32

Một phương pháp phổ biến là sử dụng VALUESmệnh đề và CROSS APPLYhai cột được đặt bí danh là một cột duy nhất, sau đó lấy MINMAXcủa mỗi cột .

SELECT MIN(x.CombinedDate) AS least, MAX(x.CombinedDate) AS greatest
FROM   dbo.Users AS u
CROSS APPLY ( VALUES ( u.CreationDate ), ( u.LastAccessDate )) AS x ( CombinedDate );

Có nhiều cách viết khác, ví dụ như sử dụng UNION ALL

SELECT MIN(x.CombinedDate) AS least, MAX(x.CombinedDate) AS greatest
FROM   dbo.Users AS u
CROSS APPLY ( SELECT u.CreationDate UNION ALL SELECT u.LastAccessDate ) AS x(CombinedDate);

Tuy nhiên, các kế hoạch truy vấn kết quả dường như là giống nhau.


12

Bạn cũng có thể đặt các giá trị nội tuyến trong một truy vấn con. Như thế này:

select (select max(i) from (values (1), (2), (5), (1), (6)) AS T(i)) greatest,
       (select min(i) from (values (1), (2), (5), (1), (6)) AS T(i)) least

3

Đây sẽ là một khởi đầu tốt -

CASE WHEN A > B THEN A ELSE B END

Đó là một gợi ý hay nhưng nó đã được đề cập trong câu hỏi với "không kiểm soát điều kiện vào các tuyên bố CASE"
Evan Carroll

3

Tương đương cao nhất:

IIF(@a < @b, @a, @b)

Tương đương TUYỆT VỜI:

IIF(@a > @b, @a, @b)

3
Làm thế nào để bạn làm điều đó cho ba hoặc nhiều giá trị, ví dụ least(5,6,7,8,9)?
a_horse_with_no_name

@a_horse_with_no_name Sử dụng IIF lồng nhau
Elnur

Cách tiếp cận này sẽ nhanh chóng trở thành thách thức để đọc và xác minh ... Làm thế nào để nó vượt qua về mặt hiệu suất?
Dodecaphone

0

Tôi tạo các hàm do người dùng định nghĩa, vd

create function dbo.udf_LeastInt(@a int, @b int)
returns int
with schemabinding
as
begin
  return case when @a <= @b then @a 
              when @b < @a  then @b
              else null
         end
end

Mặc dù nó có thể hoạt động trong các trường hợp đơn giản, tuy nhiên có một số vấn đề với cách tiếp cận này:

  • Khó chịu là bạn phải tạo các chức năng riêng biệt cho từng loại dữ liệu.
  • Nó chỉ xử lý 2 tham số, vì vậy người ta có thể cần nhiều chức năng hơn để xử lý nhiều tham số hoặc sử dụng các cuộc gọi lồng nhau của cùng chức năng.
  • Nó sẽ tốt hơn (hiệu quả hơn) như một TVF nội tuyến hơn là một hàm vô hướng. Điều đó có liên quan đến việc thực hiện các hàm vô hướng. Có rất nhiều blog về nó, xem ví dụ SQL 101: Các chất ức chế song song - Hàm xác định người dùng vô hướng (của John Kehayias .
  • Nếu một trong các đối số là null, nó sẽ trả về null. Điều này khớp với những gì người leastvận hành làm trong Oracle và MySQL, nhưng khác với Postgres. Nhưng điều này chống lại null làm cho nó dài dòng hơn (nếu bạn biết họ sẽ không null, một đồng bằng case when @a <= @b then @a else @b endsẽ hoạt động).

Tất cả trong tất cả có thể tốt hơn để viết ra casetuyên bố lâu dài nếu hiệu suất có vấn đề. Tôi thậm chí đã dùng đến việc tạo các casecâu lệnh lồng nhau ở phía máy khách khi có một vài giá trị để so sánh.


0

Tôi đã có ý định thêm bình luận vào câu trả lời @ ed-avis, nhưng không thể làm như vậy, vì thiếu danh tiếng, vì vậy đăng bài này dưới dạng phần mở rộng cho câu trả lời của anh ấy.

Tôi đã loại bỏ nhược điểm của "Khó chịu là bạn phải tạo các chức năng riêng biệt cho từng loại dữ liệu." Sử dụng SQL_VariANT .

Đây là cách thực hiện của tôi:

CREATE OR ALTER FUNCTION my_least(@a SQL_VARIANT, @b SQL_VARIANT)
returns SQL_VARIANT
with schemabinding
as
begin
  return case when @a <= @b then @a 
              when @b < @a  then @b
              WHEN @a IS NULL THEN @b
              WHEN @b IS NULL THEN @a
              else null
         end
END;

Ngoài ra chức năng này xử lý NULL giống như phiên bản postgresql.

Chức năng này có thể được thêm vào DB để thuận tiện, nhưng chậm hơn 10 lần so với sử dụng tích hợp IIF. Các thử nghiệm của tôi cho thấy, chức năng như vậy với loại chính xác ( datetime ) thực hiện giống như phiên bản sql_variant .

PS Tôi chạy một số thử nghiệm trên tập dữ liệu gồm các giá trị 350k và dường như hiệu suất là như nhau, sql_variant nhanh hơn một chút, nhưng tôi tin rằng đó chỉ .

Nhưng bất kỳ cách nào phiên bản IIF là 10 lần nhanh hơn lần !!!

Tôi chưa thử nghiệm nội tuyến CASE WHENnhưng về cơ bản cho t-sql IIF cũng giống như trường hợp và iif được chuyển đổi bởi trình tối ưu hóa thành biểu thức trường hợp.

Việc IIF được dịch sang CASE cũng có tác động đến các khía cạnh khác trong hành vi của chức năng này.

KẾT LUẬN: Sử dụng IIF nhanh hơn nếu hiệu năng hoạt động, nhưng để tạo mẫu hoặc nếu cần rõ ràng hơn về mã và không cần tính toán lớn, có thể sử dụng chức năng được cung cấp.


1
Bạn nói rằng "sqlvariant nhanh hơn một chút" và "phiên bản IIF nhanh hơn gấp 10 lần". nhanh hơn cái gì?
ypercubeᵀᴹ

Phiên bản Sql ver có tốc độ tương đương với phiên bản concreete, như được cung cấp bởi một câu trả lời khác. Trong thử nghiệm của tôi, nó là 80ms fater (hết từ 15 giây), tôi cho rằng đó chỉ là lỗi thống kê. Và sử dụng iif(a<b, a, b) nhanh hơn 10 lần so với bất kỳ chức năng nào do người dùng xác định.
Bogdan Mart

Để rõ ràng, tôi đã sử dụng mã của mình với sql_variant được thay thế bằng datetime, như là hàm thứ hai. Sau khi kiểm tra, có vẻ như sql_variant không thêm bất kỳ chi phí nào, nhưng các chức năng do người dùng xác định chậm hơn so với tích hợp
Bogdan Mart

Nhưng có bất kỳ chức năng nào trong số này - bao gồm IIF()- nhanh hơn sử dụng CASEbiểu thức không? Quan điểm của tôi là, vì bạn đã gặp rắc rối khi kiểm tra hiệu suất, bạn nên kiểm tra tất cả các phương pháp / câu trả lời được đề xuất.
ypercubeᵀᴹ

1
@ yper-crazyhat-cubeᵀᴹ cập nhật câu trả lời. Không chỉnh sửa thêm, chỉ muốn thêm nhận xét về câu trả lời của sql_variant vào câu trả lời của ed-avis, nhưng do thiếu gợi ý đã phải viết câu trả lời mở rộng :-)
Bogdan Mart
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.