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


77

Tôi muốn lấy các bản ghi của tháng trước dựa trên trường db table [thành viên] "date_create" của tôi.

Sql để làm điều này là gì?

Để làm rõ, tháng trước - 1/8/2009 đến 31/8/2009

Nếu hôm nay là 3/1/2010, tôi sẽ cần lấy hồ sơ từ 1/12/2009 đến 31/12/2009.


2
"Tháng trước" có nghĩa là "30 ngày qua", "tất cả các ngày trong tháng trước" hoặc "tất cả các ngày trong tháng hiện tại"?
Cellfish

Cú pháp tốt nhất cũng tùy thuộc vào việc bạn đang sử dụng SQL 2005 (hoặc cũ hơn) với trường DATETIME hay SQL 2008 với trường DATE.
eidylon

4
Về DATEDIFF(month, date_created, GETDATE()) = 1thì sao? Điều đó sẽ không hoạt động tốt?
Philipp M

Câu trả lời:


115
SELECT * 
FROM Member
WHERE DATEPART(m, date_created) = DATEPART(m, DATEADD(m, -1, getdate()))
AND DATEPART(yyyy, date_created) = DATEPART(yyyy, DATEADD(m, -1, getdate()))

Bạn cần kiểm tra tháng và năm.


2
trong trường hợp của tôi SELECT * FROM Member WHERE DATEPART(m, date_created) = DATEPART(m, DATEADD(m, -1, getdate())) AND DATEPART(yy, date_created) = DATEPART(yy, DATEADD(m, -1, getdate()))hoạt động hoàn hảo
gofor.net

9
Cách tiếp cận này sẽ bỏ qua bất kỳ chỉ mục nào trên bảng và thực hiện quét bảng (hoặc chỉ mục theo cụm) mỗi khi nó được chạy. Bảng càng lớn thì truy vấn sẽ mất nhiều thời gian hơn.
mrdenny

5
Bạn phải sử dụng yyyy thay vì y
insert

105

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 theo ý muốn, â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 nó (bao gồm ngầm định, như for 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ý các 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à một longhoặc BIGINTEGERđếm mili / 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 các 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 làm điều đó lần thứ hai để 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 SQL Server cụ thể và kiểu dữ liệu cột, việc 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 việc chọn sai dữ liệu . 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 "tiếp theo" 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 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). Cách chính xác sau đó có dạng:

WHERE date_created >= @startOfPreviousMonth AND date_created < @startOfCurrentMonth

Cho rằng chỉ có một tháng, @startOfPreviousMonthcó thể dễ dàng thay thế cho / bắt nguồn bằng:

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 theo cách sau:

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

Một lời giải thích nhanh ở đây. Giá trị ban đầu DATEDIFF(...)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 đầu tháng hiện tại . 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.


8
Tôi thực sự ước ngay cả khi phải trả giá bằng danh tiếng, tôi có thể bình chọn điều này nhiều hơn một lần. Làm tốt.
Knox

2
Bạn là một thiên tài! Tôi đánh giá cao một phản hồi bằng văn bản tốt, không coi thường, chỉ thông báo. Tôi cũng đồng ý với @knox
bird2920

Đây sẽ là câu trả lời tốt nhất. Cảm ơn bạn đã biết thêm thông tin rằng "BETWEEN" sẽ không hoạt động trong trường hợp này, vì nó sẽ mất thêm một ngày.
cosan

11

Thêm các tùy chọn đã được cung cấp cho đến nay sẽ không sử dụng các chỉ mục của bạn.

Một cái gì đó như thế này sẽ thực hiện thủ thuật và sử dụng một chỉ mục trên bảng (nếu có).

DECLARE @StartDate DATETIME, @EndDate DATETIME
SET @StartDate = dateadd(mm, -1, getdate())
SET @StartDate = dateadd(dd, datepart(dd, getdate())*-1, @StartDate)
SET @EndDate = dateadd(mm, 1, @StartDate)

SELECT *
FROM Member
WHERE date_created BETWEEN @StartDate AND @EndDate

Xin lỗi vì đã phản đối, nhưng nó không hoạt động: Hãy thử '12 / 31/2013 11:59 'cho một mẫu đếm ngược (trả về các hàng từ' 2013-10-30 11: 59: 00.000 'và' 2013-11-30 11: 59: 00.000 'trên SQL Server).
Daniel Cotter

1
getdate () cung cấp cho bạn thời gian hiện tại. Tôi nghĩ bạn nên dành thời gian từ 12:00 sáng (đầu ngày). Câu trả lời @Rokas là đúng. In thời gian bắt đầu và thời gian kết thúc nếu bạn muốn xem.
madhu_karnati

10
DECLARE @StartDate DATETIME, @EndDate DATETIME
SET @StartDate = DATEADD(mm, DATEDIFF(mm,0,getdate())-1, 0)
SET @EndDate = DATEADD(mm, 1, @StartDate)

SELECT *
FROM Member
WHERE date_created BETWEEN @StartDate AND @EndDate

Một bản nâng cấp cho giải pháp của mrdenny, theo cách này, bạn nhận được chính xác tháng trước từ YYYY-MM-01


3

Tháng trước coi như cho đến ngày cuối cùng của tháng. Ngày 31/01/2016 ở đây là ngày cuối cùng của tháng sẽ là ngày 31 tháng 1, không tương tự như 30 ngày trước.

SELECT CONVERT(DATE, DATEADD(DAY,-DAY(GETDATE()),GETDATE()))

1

Một cách để làm điều đó là sử dụng hàm DATEPART :

select field1, field2, fieldN from TABLE where DATEPART(month, date_created) = 4 
and DATEPART(year, date_created) = 2009

sẽ trả lại tất cả các ngày trong tháng tư. Đối với tháng trước (tức là tháng trước đến tháng hiện tại), bạn cũng có thể sử dụng GETDATEDATEADD :

select field1, field2, fieldN from TABLE where DATEPART(month, date_created) 
= (DATEPART(month, GETDATE()) - 1) and 
DATEPART(year, date_created) = DATEPART(year, DATEADD(m, -1, GETDATE()))

3
Cách tiếp cận này sẽ bỏ qua bất kỳ chỉ mục nào trên bảng và thực hiện quét bảng (hoặc chỉ mục theo cụm) mỗi khi nó được chạy. Bảng càng lớn thì truy vấn sẽ mất nhiều thời gian hơn.
mrdenny

1
declare @PrevMonth as nvarchar(256)

SELECT @PrevMonth = DateName( month,DATEADD(mm, DATEDIFF(mm, 0, getdate()) - 1, 0)) + 
   '-' + substring(DateName( Year, getDate() ) ,3,4)

1

Truy vấn SQL để chỉ nhận bản ghi của tháng hiện tại

SELECT * FROM CUSTOMER
WHERE MONTH(DATE) = MONTH(CURRENT_TIMESTAMP) AND YEAR(DATE) = YEAR(CURRENT_TIMESTAMP);

0
select * from [member] where DatePart("m", date_created) = DatePart("m", DateAdd("m", -1, getdate())) AND DatePart("yyyy", date_created) = DatePart("yyyy", DateAdd("m", -1, getdate()))

2
Mặc dù mã này có thể trả lời câu hỏi, nhưng việc cung cấp thêm ngữ cảnh liên quan đến lý do và / hoặc cách mã này trả lời câu hỏi sẽ cải thiện giá trị lâu dài của nó.
β.εηοιτ.βε

0
DECLARE @StartDate DATETIME, @EndDate DATETIME    
SET @StartDate = DATEADD(mm, DATEDIFF(mm, 0, getdate()) - 1, 0)    
SET @EndDate = dateadd(dd, -1, DATEADD(mm, 1, @StartDate))

SELECT * FROM Member WHERE date_created BETWEEN @StartDate AND @EndDate 

và một nâng cấp khác cho giải pháp của mrdenny.
Nó cũng cho biết chính xác ngày cuối cùng của tháng trước.


0
WHERE 
    date_created >= DATEADD(MONTH, DATEDIFF(MONTH, 31, CURRENT_TIMESTAMP), 0)
    AND date_created < DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP), 0)

Một chút giải thích?
cheesemacfly

0

Tôi đến từ Oracle env và tôi sẽ làm như thế này trong Oracle:

select * from table
where trunc(somedatefield, 'MONTH') =
trunc(sysdate -INTERVAL '0-1' YEAR TO MONTH, 'MONTH')

Ý tưởng: Tôi đang chạy một báo cáo đã lên lịch của tháng trước (từ ngày 1 đến ngày cuối cùng của tháng, không có cửa sổ). Đây có thể là chỉ mục không thân thiện, nhưng dù sao thì Oracle cũng xử lý ngày tháng nhanh chóng. Có một cách đơn giản và ngắn gọn tương tự trong MS SQL không? Câu trả lời so sánh năm và tháng riêng biệt có vẻ ngớ ngẩn đối với người dùng Oracle.


0

Bạn có thể nhận được các bản ghi tháng trước với truy vấn này

SELECT * FROM dbo.member d 
WHERE  CONVERT(DATE, date_created,101)>=CONVERT(DATE,DATEADD(m, datediff(m, 0, current_timestamp)-1, 0)) 
and CONVERT(DATE, date_created,101) < CONVERT(DATE, DATEADD(m, datediff(m, 0, current_timestamp)-1, 0),101) 

0

Tôi không nghĩ rằng giải pháp được chấp nhận là rất thân thiện với chỉ mục, tôi sử dụng các dòng sau để thay thế

select * from dbtable where the_date >= convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120) and the_date <= dateadd(ms, -3, convert(varchar(10),DATEADD(m, 0, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120));

Hoặc đơn giản (cái này là tốt nhất).

select * from dbtable where the_date >= convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120) and the_date < SELECT convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120);

Một số trợ giúp

-- Get the first of last month
SELECT convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120);
-- Get the first of current month
SELECT convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120);
--Get the last of last month except the last 3milli seconds. (3miliseconds being used as SQL express otherwise round it up to the full second (SERIUSLY MS)
SELECT dateadd(ms, -3, convert(varchar(10),DATEADD(m, 0, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120));

-1

Trong máy chủ Sql trong một tháng qua:

select * from tablename 
where order_date > DateAdd(WEEK, -1, GETDATE()+1) and order_date<=GETDATE()

-1
DECLARE @curDate INT = datepart( Month,GETDATE())
IF (@curDate = 1)
    BEGIN
        select * from Featured_Deal
        where datepart( Month,Created_Date)=12 AND datepart(Year,Created_Date) = (datepart(Year,GETDATE())-1)

    END
ELSE
    BEGIN
        select * from Featured_Deal
        where datepart( Month,Created_Date)=(datepart( Month,GETDATE())-1) AND datepart(Year,Created_Date) = datepart(Year,GETDATE())

    END 

-1
DECLARE @StartDate DATETIME, @EndDate DATETIME
SET @StartDate = dateadd(mm, -1, getdate())
SET @StartDate = dateadd(dd, datepart(dd, getdate())*-1, @StartDate)
SET @EndDate = dateadd(mm, 1, @StartDate)
set @StartDate = DATEADD(dd, 1 , @StartDate)

-1

Cách tôi đã khắc phục sự cố tương tự là thêm Tháng vào phần CHỌN của mình

Month DATEADD(day,Created_Date,'1971/12/31') As Month

và hơn tôi đã thêm câu lệnh WHERE

Month DATEADD(day,Created_Date,'1971/12/31') = month(getdate())-1

-1

Nếu bạn đang tìm kiếm tháng trước, hãy thử điều này,

SELECT
FROM  #emp 
WHERE DATEDIFF(MONTH,CREATEDDATE,GETDATE()) = 1

Nếu bạn đang tìm kiếm tháng trước, hãy thử điều này,

SELECT
FROM #emp
WHERE DATEDIFF(day,CREATEDDATE,GETDATE()) between 1 and 30

1
Vui lòng đọc các câu trả lời trước để biết tại sao điều này không hoạt động và \ hoặc không phải là cách chính xác để thực hiện trước khi mọi người phản đối. Và có thể bạn muốn xóa câu trả lời của mình.
Cetin Basoz

Xin chào, chào mừng bạn đến với Stack Overflow. Khi trả lời một câu hỏi đã có nhiều câu trả lời (17!), Hãy đảm bảo thêm một số thông tin chi tiết bổ sung về lý do tại sao câu trả lời soạn vội mà bạn đang cung cấp là thực chất và không chỉ lặp lại những gì đã được người đăng gốc kiểm tra. Điều này đặc biệt quan trọng trong các câu trả lời "chỉ có mã" như của bạn.
chb

-1

Một truy vấn đơn giản phù hợp với tôi là:

chọn * từ bảng trong đó DATEADD (tháng, 1, DATEFIELD)> = getdate ()


-1

Nếu bạn đang tìm kiếm dữ liệu tháng trước:

date(date_created)>=date_sub(date_format(curdate(),"%Y-%m-01"),interval 1 month) and 
date(date_created)<=date_sub(date_format(curdate(),'%Y-%m-01'),interval 1 day)

Điều này cũng sẽ hoạt động khi năm thay đổi. Nó cũng sẽ hoạt động trên MySQL.

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.