Tại sao CROSS ỨNG DỤNG * không * gặp lỗi cột không hợp lệ trong truy vấn này?


8

Tôi đang viết một số mã để truy vấn một số DMV. Một số cột có thể tồn tại hoặc không tồn tại trong DMV tùy thuộc vào phiên bản SQL. Tôi tìm thấy một gợi ý thú vị trực tuyến làm thế nào để bỏ qua kiểm tra cụ thể bằng cách sử dụng CROSS APPLY.

Truy vấn dưới đây là một ví dụ về mã để đọc DMV cho cột có khả năng bị thiếu. Mã tạo một giá trị mặc định cho cột và sử dụng CROSS APPLYđể trích xuất cột thực tế, nếu nó tồn tại, từ DMV.

Cột mà mã cố gắng trích xuất, BogusColumn, không tồn tại. Tôi hy vọng truy vấn bên dưới sẽ tạo ra lỗi về tên cột không hợp lệ ... nhưng không. Nó trả về NULL mà không có lỗi.

Tại sao mệnh đề CROSS ỨNG DỤNG bên dưới KHÔNG dẫn đến lỗi "tên cột không hợp lệ"?

declare @x int
select @x = b.BogusColumn
from
(
    select cast(null as int) as BogusColumn
) a
cross apply
(
    select BogusColumn from sys.dm_exec_sessions
) b;
select @x;

Nếu tôi chạy truy vấn CROSS APPLYriêng:

select BogusColumn from sys.dm_exec_sessions;

Tôi nhận được một lỗi dự kiến ​​về một tên cột không hợp lệ:

Msg 207, Level 16, State 1, Line 9
Invalid column name 'BogusColumn'.

Nếu tôi thay đổi tên cột DMV thành BogusColumn2 để làm cho nó là duy nhất, tôi sẽ gặp lỗi tên cột dự kiến:

select a.BogusColumn1, b.BogusColumn2
from
(
    select cast(null as int) as BogusColumn1
) a
cross apply
(
    select BogusColumn2 from sys.dm_exec_sessions
) b

Tôi đã thử nghiệm hành vi này trên các phiên bản SQL 2012 đến SQL 2017 và hành vi này phù hợp với tất cả các phiên bản.


5
Mặc dù hành vi này có thể dự đoán được, nhưng đây cũng là một vụ hack cực kỳ khủng khiếp. Bất cứ ai nghĩ ra nó đều xứng đáng với cả danh tiếng, và một cái tát vào cổ tay vì đã đưa ra một cái bẫy bảo trì như thế này. Nó chỉ chấp nhận được về việc bao gồm các khác biệt về phiên bản trong chế độ xem hệ thống và không có gì khác.
Jeroen Mostert

3
Tôi đồng ý với @JeroenMostert. Để tránh các lỗi gây ra bởi sự thay đổi đáng ngạc nhiên trong độ phân giải cột LUÔN LUÔN sử dụng các bí danh bảng từ trong cột. Tôi thấy sản xuất giảm vì ai đó đã thêm một cột mới vào bảng gây ra hiệu ứng tương tự.
Piotr

1
Câu hỏi tuyệt vời! Và danh tiếng cho @Piotr khi đề cập đến răng cưa cột. Tôi sử dụng ỨNG DỤNG rất nhiều, thường được lồng và không có bí danh, mọi thứ có thể trở nên khá khó hiểu một cách nhanh chóng.
Alan Burstein

Tôi đồng ý đây là cả thông minh và hack xấu xí. Tôi sẽ không muốn sử dụng mã này trong mã sản xuất, nhưng tôi muốn sử dụng nó để tránh các vấn đề về phiên bản trong DMV. Các truy vấn kiểu DBA để phân tích hoạt động của máy chủ đơn giản hơn nhiều với phương thức này thay vì tất cả các phiên bản kiểm tra mà tôi thường phải làm. IF @MajorVersion >= @SQL2016 AND @MinorVersion >= @SQL2016SP1 BEGIN /* write and execute dynamic SQL, etc. */ END
Paul Williams

Câu trả lời:


7

BogusColumn được định nghĩa là một cột hợp lệ trong truy vấn đầu tiên.

Khi chúng tôi đang áp dụng áp dụng chéo, nó đang sử dụng độ phân giải cột như sau:
1. Nó tìm cột 'BogusColumn' trong truy vấn thứ 2 (dmv)
2. Nếu cột tồn tại trong dmv, nó sẽ được phân giải thành dmv
3 . Nếu cột không tồn tại trong dmv, nó sẽ tìm cột này trong truy vấn bên ngoài (cột trên cùng) và sử dụng giá trị được cung cấp ở đó.

Nói cách khác, khi cột không có thật không được xác định trong dạng xem, truy vấn cuối cùng sẽ hoạt động như sau:

select * from
(
    select cast(null as int) as BogusColumn
) a
cross apply
(
    select a.BogusColumn AS BogusColumn from sys.dm_exec_sessions
) b;

Nếu được xác định, truy vấn sẽ giải quyết:

select * from
(
    select cast(null as int) as BogusColumn
) a
cross apply
(
    select s.BogusColumn AS BogusColumn from sys.dm_exec_sessions as s
) b;
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.