Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Nhận các bản ghi của tháng trước trong máy chủ SQL

Tất cả các câu trả lời hiện có (đang hoạt động) có một trong hai vấn đề:

  1. Họ sẽ bỏ qua các chỉ số trên cột đang được tìm kiếm
  2. Ý chí (có khả năng) chọn dữ liệu không có mục đích, âm thầm làm hỏng kết quả của bạn.

1. Các chỉ số bị Bỏ qua:

Đối với hầu hết các phần, khi một cột đang được tìm kiếm có một hàm được gọi trên đó (bao gồm ẩn ý, ​​như đối với CAST ), trình tối ưu hóa phải bỏ qua các chỉ số trên cột và tìm kiếm qua mọi bản ghi. Đây là một ví dụ nhanh:

Chúng tôi đang xử lý dấu thời gian và hầu hết các RDBMS có xu hướng lưu trữ thông tin này dưới dạng giá trị ngày càng tăng của một số loại, thường là long hoặc BIGINTEGER đếm milli- / nano giây. Do đó, thời gian hiện tại trông / được lưu trữ như sau:

1402401635000000  -- 2014-06-10 12:00:35.000000 GMT

Bạn không thấy giá trị 'Năm' ('2014' ) trong đó, phải không? Trên thực tế, có một chút toán học phức tạp để dịch qua lại. Vì vậy, nếu bạn gọi bất kỳ hàm phần trích xuất / ngày nào trên cột được tìm kiếm, máy chủ phải thực hiện tất cả phép toán đó chỉ để tìm ra liệu bạn có thể đưa nó vào kết quả hay không. Trên các bảng nhỏ, đây không phải là một vấn đề, nhưng khi tỷ lệ phần trăm hàng được chọn giảm, điều này trở nên lớn hơn và lớn hơn. Sau đó, trong trường hợp này, bạn đang thực hiện lần thứ hai khi hỏi về MONTH ... tốt, bạn sẽ có được bức tranh.

2. Dữ liệu ngoài ý muốn:

Tùy thuộc vào phiên bản cụ thể của SQL Server và kiểu dữ liệu cột, sử dụng BETWEEN (hoặc các phạm vi giới hạn trên bao gồm tương tự:<= ) có thể dẫn đến dữ liệu được chọn sai. Về cơ bản, bạn có thể kết thúc việc bao gồm dữ liệu từ nửa đêm của ngày "hôm sau" hoặc loại trừ một số phần của bản ghi của ngày "hiện tại".

Những gì bạn nên đang làm:

Vì vậy, chúng tôi cần một cách an toàn cho dữ liệu của mình và sẽ sử dụng các chỉ số (nếu khả thi). Khi đó, cách chính xác có dạng:

WHERE date_created >= @startOfPreviousMonth AND date_created < @startOfCurrentMonth

Do chỉ có một tháng, @startOfPreviousMonth có thể dễ dàng thay thế cho / bắt nguồn bởi:

DATEADD(month, -1, @startOCurrentfMonth)

Nếu bạn cần lấy ngày bắt đầu của tháng hiện tại trong máy chủ, bạn có thể thực hiện việc đó thông qua cách sau:

DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)

Một lời giải thích nhanh ở đây. DATEDIFF(...) ban đầu sẽ nhận được sự khác biệt giữa thời điểm bắt đầu kỷ nguyên hiện tại (0001-01-01 - AD, CE, bất cứ điều gì), về cơ bản trả về một số nguyên lớn. Đây là số tháng tính đến thời điểm bắt đầu của hiện tại tháng. Sau đó, chúng tôi thêm số này vào đầu kỷ nguyên, tức là vào đầu tháng nhất định.

Vì vậy, tập lệnh đầy đủ của bạn có thể / phải trông giống như sau:

DECLARE @startOfCurrentMonth DATETIME
SET @startOfCurrentMonth = DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)

SELECT *
FROM Member
WHERE date_created >= DATEADD(month, -1, @startOfCurrentMonth) -- this was originally    misspelled
      AND date_created < @startOfCurrentMonth

Do đó, tất cả các hoạt động ngày tháng chỉ được thực hiện một lần, trên một giá trị; trình tối ưu hóa miễn phí sử dụng các chỉ số và không có dữ liệu sai nào được đưa vào.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm thế nào để tìm tổng của nhiều cột trong một bảng trong SQL Server 2005?

  2. Loại bỏ đệm khi gửi kết quả truy vấn trong email từ SQL Server (T-SQL)

  3. Sử dụng Excel VBA để chạy truy vấn SQL

  4. Làm cách nào để chèn một bản ghi chỉ có các giá trị mặc định?

  5. Thay đổi Chế độ nghi ngờ cơ sở dữ liệu SQL thành Chế độ bình thường với truy vấn