2012-03-29 39 views
9

tôi có Gói ssis chạy vào ngày làm việc (mon-Fri). nếu tôi nhận được tập tin vào thứ ba, nền (DB), phải mất ngày làm việc trước đó và thực hiện một số giao dịch. Nếu tôi chạy công việc vào thứ sáu, nó phải lấy ngày thứ hai và xử lý các giao dịch.Cách nhận ngày làm việc trước đó trong một tuần với ngày làm việc hiện tại bằng máy chủ sql

tôi đã sử dụng các truy vấn dưới đây để có được ngày kinh doanh trước

Select Convert(varchar(50), Position_ID) as Position_ID, 
     TransAmount_Base, 
     Insert_Date as InsertDate 
    from tblsample 
Where AsOfdate = Dateadd(dd, -1, Convert(datetime, Convert(varchar(10), '03/28/2012', 101), 120)) 
Order By Position_ID 

nếu tôi thực hiện truy vấn này tôi sẽ có được kết quả của ngày hôm qua Transactios. nếu tôi chạy cùng một truy vấn vào thứ hai, nó phải lấy các giao dịch thứ Sáu thay vì các ngày chủ nhật.

Trả lời

33
SELECT DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE()) 
         WHEN 'Sunday' THEN -2 
         WHEN 'Monday' THEN -3 
         ELSE -1 END, DATEDIFF(DAY, 0, GETDATE())) 

Tôi thích sử dụng DATENAME cho những thứ như thế này trên DATEPART vì nó loại bỏ sự cần thiết của Thiết DATEFIRST Và đảm bảo rằng các biến thể trên các thiết lập thời gian/ngày trên máy địa phương không ảnh hưởng đến kết quả. Cuối cùng, DATEDIFF(DAY, 0, GETDATE()) sẽ xóa phần thời gian của GETDATE() xóa cần phải chuyển đổi thành varchar (chậm hơn nhiều).


EDIT (trên gần 2 năm)

Câu trả lời này là rất sớm trong SO sự nghiệp của tôi và nó làm phiền tôi mỗi lần nó được bỏ phiếu tán vì tôi không còn đồng ý với tình cảm của việc sử dụng DATENAME.

Một giải pháp rubust nhiều hơn nữa sẽ là:

SELECT DATEADD(DAY, CASE (DATEPART(WEEKDAY, GETDATE()) + @@DATEFIRST) % 7 
         WHEN 1 THEN -2 
         WHEN 2 THEN -3 
         ELSE -1 
        END, DATEDIFF(DAY, 0, GETDATE())); 

này sẽ làm việc cho tất cả các ngôn ngữ và các thiết lập DATEFIRST.

+0

Sử dụng 'DATENAME' để tránh cần biết' DATEFIRST', nhưng vẫn hoàn thành việc bỏ qua đó là ngôn ngữ cụ thể? –

+0

Rất tốt Tuy nhiên, tôi đã bắt gặp nhiều tình huống hơn trong đó các xung đột của DATEFIRST là một vấn đề hơn là các tình huống xung đột ngôn ngữ là một vấn đề.Ví dụ, nếu bạn tạo một UDF trong cơ sở dữ liệu, bạn không thể xác định ngày đầu tiên trong UDF, bạn sẽ phụ thuộc vào truy vấn gọi hàm để đặt ngày giờ đầu tiên chính xác (hoặc không đặt ngày bắt đầu khác), tôi có nhiều khả năng người dùng sẽ cần phải thiết lập một datefirst khác hơn là thiết lập một ngôn ngữ khác (theo kinh nghiệm của tôi). – GarethD

+1

Để xây dựng thêm, tôi đã từng làm việc trong một công ty nơi tuần lễ chạy thứ tư vào thứ ba để bán giấy và thứ Sáu đến thứ Năm cho Telesales, Chúng tôi có thể sử dụng cùng một truy vấn để báo cáo điều này bằng cách thiết lập ngày cho phù hợp, điều này sẽ được hiển thị bất kỳ việc sử dụng DATEPART (NGÀY, [ngày]) để xác định ngày cuối tuần vô dụng. Đây là lý do tại sao tôi ** thích ** để sử dụng datename. Tôi không bênh vực rằng nó hoàn hảo. – GarethD

0
select 
    dateadd(dd, 
      case DATEPART(dw, getdate()) 
      when 1 
      then -2 
      when 2 
      then -3 
      else -1 
     end, GETDATE()) 
+0

Sử dụng 'DATEPART (dw ...' mà không biết 'cái khung cảnh DATEFIRST' là [mơ hồ] (http: //msdn.microsoft.com/en-us/library/ms174420.aspx) Đừng làm điều đó –

1

Giải pháp đơn giản nhất để tìm ngày làm việc trước đó là sử dụng calendar table với cột được gọi là IsBusinessDay hoặc tương tự. Các truy vấn của bạn là một cái gì đó như thế này:

select max(BaseDate) 
from dbo.Calendar c 
where c.IsBusinessDay = 0x1 and c.BaseDate < @InputDate 

Vấn đề với việc sử dụng các chức năng là khi (không nếu) bạn phải tạo ngoại lệ cho bất cứ lý do (ngày lễ quốc gia, vv) mã nhanh chóng trở thành unmaintainable; với bảng, bạn chỉ cần UPDATE một giá trị duy nhất. Một bảng cũng giúp bạn trả lời các câu hỏi dễ dàng hơn nhiều như "có bao nhiêu ngày làm việc giữa ngày X và Y", điều này khá phổ biến trong các tác vụ báo cáo.

3

Sau đó thế nào về:

declare @dt datetime='1 dec 2012' 

select case when [email protected]@DATEFIRST=DATEPART(dw,@dt) 
      then DATEADD(d,-2,@dt) 
     when ([email protected]@DATEFIRST)%7=DATEPART(dw,@dt)%7 
      then DATEADD(d,-3,@dt) 
     else DATEADD(d,-1,@dt) 
    end 
0

nhờ những lời khuyên ở trên, tôi đã có một biến thể nhẹ trên truy vấn trong đó người sử dụng tôi cần tất cả các giá trị cho các ngày kinh doanh trước đó. Ví dụ, hôm nay là thứ Hai nên anh ấy cần mọi thứ từ thứ Sáu tuần trước vào lúc nửa đêm đến Thứ Bảy lúc nửa đêm. Tôi đã làm điều này bằng cách sử dụng một kết hợp ở trên, và "giữa", chỉ khi có ai quan tâm. Tôi không phải là một techie lớn.

-- Declare a variable for the start and end dates. 
declare @StartDate as datetime 
declare @EndDate as datetime 

SELECT @StartDate = DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE()) 
WHEN 'Sunday' THEN -2 
WHEN 'Monday' THEN -3 
    ELSE -1 END, DATEDIFF(DAY, 0, GETDATE())) 
select @EndDate = @StartDate + 1 
select @StartDate , @EndDate 
-- Later on in the query use "between" 
and mydate between @StartDate and @EndDate 
1

Bạn có thể dễ dàng thực hiện cuộc gọi hàm này, thêm thông số thứ hai để thay thế GetDate() với bất kỳ ngày nào bạn muốn. Nó sẽ hoạt động cho bất kỳ ngày nào trong tuần, tại bất kỳ phạm vi ngày nào, nếu bạn thay đổi GetDate(). Nó sẽ không thay đổi ngày nếu ngày nào trong tuần là ngày đầu vào (getdate())

Declare @DayOfWeek As Integer = 2 -- Monday 

Select DateAdd(Day, ((DatePart(dw,GetDate()) + (7 - @DayOfWeek)) * -1) % 7, Convert(Date,GetDate())) 
Các vấn đề liên quan