Đề cập đến một Bí danh Cột trong Điều khoản WHERE


166
SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
WHERE daysdiff > 120

tôi có

"ngày tên cột không hợp lệ".

Maxlogtm là một trường datetime. Đó là những thứ nhỏ khiến tôi phát điên.


không chắc chắn cho mysql, nhưng có lẽ bí danh cần được bọc trong tích tắc `daysdiff`.
Ash Burlaczenko

Câu trả lời:


194
SELECT
   logcount, logUserID, maxlogtm,
   DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
WHERE ( DATEDIFF(day, maxlogtm, GETDATE() > 120)

Thông thường bạn không thể tham khảo các bí danh trường trong WHEREmệnh đề. (Hãy nghĩ về nó như toàn bộ SELECTbao gồm các bí danh, được áp dụng sau WHEREmệnh đề.)

Nhưng, như đã đề cập trong các câu trả lời khác, bạn có thể buộc SQL xử lý SELECTđể được xử lý trước WHEREmệnh đề. Điều này thường được thực hiện với dấu ngoặc đơn để buộc thứ tự hoạt động hợp lý hoặc với Biểu thức bảng chung (CTE):

Dấu ngoặc đơn / Đăng ký:

SELECT
   *
FROM
(
   SELECT
      logcount, logUserID, maxlogtm,
      DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
   FROM statslogsummary   
) as innerTable
WHERE daysdiff > 120

Hoặc xem câu trả lời của Adam cho phiên bản CTE giống nhau.


16
Điều này là không thể trực tiếp, bởi vì theo trình tự thời gian, WHERE xảy ra trước CHỌN, đây luôn là bước cuối cùng trong chuỗi thực thi.
TÀI LIỆU

afaik nếu bí danh trong phần chọn là một truy vấn con tương quan, nó sẽ hoạt động trong khi giải pháp CTE sẽ không.
Gấu trúc Răzvan Flavius

Như Pascal đã đề cập trong câu trả lời của mình ở đây stackoverflow.com/a/38822328/282887 , bạn có thể sử dụng mệnh đề HAVING dường như hoạt động nhanh hơn các truy vấn con.
Bakhtiyor

@Bakhtiyor Câu HAVINGtrả lời không hoạt động trong hầu hết các môi trường SQL, bao gồm cả MS-SQL mà câu hỏi này đề cập đến. (Trong T-SQL, HAVINGyêu cầu hàm tổng hợp.)
Jamie F

72

Nếu bạn muốn sử dụng bí danh trong WHEREmệnh đề của mình , bạn cần phải bọc nó trong phần chọn phụ hoặc CTE :

WITH LogDateDiff AS
(
   SELECT logcount, logUserID, maxlogtm
      , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
   FROM statslogsummary
)
SELECT logCount, logUserId, maxlogtm, daysdiff
FROM LogDateDiff
WHERE daysdiff > 120

2
Bạn có tình cờ biết làm thế nào hội chợ này hiệu quả khôn ngoan? Có thêm chi phí sử dụng CTE không?
James

5
CTE chỉ là cú pháp đẹp hơn cho truy vấn phụ, do đó hiệu suất sẽ tương tự như vậy. Theo kinh nghiệm của tôi, sự khác biệt về hiệu năng không phải là điều khiến tôi lo lắng cho các hoạt động như thế này, nhưng nó khá đơn giản để kiểm tra nó trong môi trường của bạn để xem liệu bảng / truy vấn cụ thể của bạn có bị ảnh hưởng bất lợi với điều này hay không công thức cụ thể trong mệnh đề where. Tôi nghi ngờ bạn sẽ không nhận thấy một sự khác biệt.
Adam Wenger

CTE là siêu đẹp cho đến khi bạn cố gắng sử dụng một như một truy vấn con. Tôi đã phải dùng đến việc tạo ra chúng làm khung nhìn để lồng chúng. tôi coi đây là một thiếu sót nghiêm trọng của SQL
cộng sinh

10

Cách hiệu quả nhất để làm điều đó mà không lặp lại mã của bạn là sử dụng HAVING thay vì WHERE

SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
HAVING daysdiff > 120

1
Tôi nghĩ rằng việc sử dụng HAVINGtrên các bí danh là không chuẩn (mặc dù nó hoạt động trên MySQL). Cụ thể, tôi nghĩ rằng nó không hoạt động với SQL Server.
tokland

2
Máy chủ SQL:[S0001][207] Invalid column name 'daysdiff'
Vadzim

3
Máy chủ SQL:[S0001][8121] Column 'day' is invalid in the HAVING clause because it is not contained in either an aggregate function or the GROUP BY clause.
Vadzim

9

Nếu bạn không muốn liệt kê tất cả các cột trong CTE, một cách khác để làm điều này sẽ là sử dụng outer apply:

select
    s.logcount, s.logUserID, s.maxlogtm,
    a.daysdiff
from statslogsummary as s
    outer apply (select datediff(day, s.maxlogtm, getdate()) as daysdiff) as a
where a.daysdiff > 120

6

Làm thế nào về việc sử dụng một truy vấn con (điều này làm việc cho tôi trong Mysql)?

SELECT * from (SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary) as 'your_alias'
WHERE daysdiff > 120

4

HAVING hoạt động trong MySQL theo tài liệu:

Các HAVING khoản đã được thêm vào SQL vì WHERE từ khóa có thể không được sử dụng với chức năng tổng hợp.


4

Bạn có thể tham khảo bí danh cột nhưng bạn cần xác định nó bằng cách sử dụng CROSS/OUTER APPLY:

SELECT s.logcount, s.logUserID, s.maxlogtm, c.daysdiff
FROM statslogsummary s
CROSS APPLY (SELECT DATEDIFF(day, s.maxlogtm, GETDATE()) AS daysdiff) c
WHERE c.daysdiff > 120;

Trình diễn DBFiddle

Ưu điểm:

  • định nghĩa duy nhất của biểu thức (dễ duy trì hơn / không cần sao chép-dán)
  • không cần gói toàn bộ truy vấn với CTE / lớp ngoài
  • khả năng tham khảo WHERE/GROUP BY/ORDER BY
  • hiệu suất tốt hơn có thể (thực hiện đơn)

1
Điều đáng nói là nó chỉ hoạt động trong SQL Server
Martin Zinovsky

1
@MartinZinovsky Câu hỏi được gắn thẻ sql-servert-sql:)
Lukasz Szozda

0

Đến đây tìm kiếm một cái gì đó tương tự như vậy, nhưng với một trường hợp xảy ra và kết thúc bằng cách sử dụng nơi như thế này: WHERE (CASE WHEN COLUMN1=COLUMN2 THEN '1' ELSE '0' END) = 0có lẽ bạn có thể sử dụng DATEDIFFtrong WHEREtrực tiếp. Cái gì đó như:

SELECT logcount, logUserID, maxlogtm
FROM statslogsummary
WHERE (DATEDIFF(day, maxlogtm, GETDATE())) > 120
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.