2012-03-29 10 views
9

Mam pakiet ssis, który działa w dniach roboczych (pon-pt). jeśli otrzymam plik we wtorek, tło (DB), zajmuje on poprzednią datę dnia i wykonuje pewne transakcje. Jeśli pracuję w piątek, musi on pobrać datę poniedziałku i przetworzyć transakcje.Jak uzyskać poprzedni dzień roboczy w ciągu tygodnia z bieżącym dniem roboczym przy użyciu serwera sql

Użyłem poniższego zapytania dostać poprzedni dzień Business

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 

jeśli mogę wykonać to zapytanie będę dostać wyniki wczorajszych Transactios. jeśli uruchomiłem to samo zapytanie w poniedziałek, musi on pobrać transakcje w piątek zamiast w niedziele.

Odpowiedz

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

wolę używać DATENAME na takie rzeczy jak to ponad DATEPART gdyż eliminuje potrzebę Ustawianie DATEFIRST i zapewnia, że ​​zmiany na czas/data ustawień na lokalnych komputerach nie mają wpływu na wyniki. Ostatecznie DATEDIFF(DAY, 0, GETDATE()) usunie część czasu z GETDATE(), usuwając potrzebę konwersji na varchar (znacznie wolniej).


EDIT (prawie 2 lata na)

Ta odpowiedź była bardzo wcześnie w moim SO karierze i to denerwuje mnie za każdym razem robi upvoted bo nie zgadzają się z sentymentem korzystania DATENAME.

Znacznie więcej rubust rozwiązanie byłoby:

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

to będzie działać dla wszystkich języków i ustawień DATEFIRST.

+0

Używanie 'DATENAME', aby uniknąć konieczności znajomości' DATEFIRST', ale kończąc ignorowanie, że jest to specyficzne dla języka? –

+0

Bardzo dobrze Jednak natknąłem się na więcej scenariuszy, w których konflikty DATEFIRST były problemem niż scenariusze, w których konflikt językowy był problemem.Na przykład, jeśli utworzyłeś UDF w bazie danych, nie możesz zdefiniować daty jako pierwszej w UDF, byłbyś zależny od zapytania wywołującego funkcję, aby ustawić poprawną datę (lub nie ustawiając innej daty), to s bardziej prawdopodobne, że użytkownik będzie musiał ustawić inną datę, niż ustawić inny język (według mojego doświadczenia). – GarethD

+1

celu dalszego dopracowania, kiedyś pracować w firmie, w której komisja tygodni biegnie środy do wtorku do sprzedaży papieru, a od piątku do znaleźć wady dla telesprzedaży, możemy używać tych samych zapytań zgłosić na to przez ustawienie DATEFIRST odpowiednio, to uczyniłoby dowolne użycie DATEPART (DZIEŃ, [data]) w celu oznaczenia bezużytecznych weekendów. Właśnie dlatego ** wolę ** używać nazwy. Nie twierdzę, że jest bezbłędny. – GarethD

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

Korzystanie 'datepart (dw ...' 'nie znając ustawienia DATEFIRST' jest [niejednoznaczne] (http: //msdn.microsoft.com/en-us/library/ms174420.aspx) .Nie rób tego. –

1

Najprostszym rozwiązaniem w celu znalezienia poprzedniego dnia roboczego jest użycie calendar table z kolumną o nazwie IsBusinessDay lub coś podobnego. Zapytanie jest mniej więcej tak:

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

Problem z użyciem funkcji jest to, że kiedy (jeśli nie) trzeba utworzyć wyjątki dla jakiejkolwiek przyczyny (święta narodowe itp) kod szybko staje unmaintainable; ze stołem, po prostu UPDATE pojedyncza wartość. Dzięki tabeli łatwiej jest odpowiedzieć na pytania typu "ile dni roboczych jest pomiędzy datami X i Y", które są dość powszechne w zadaniach raportowania.

3

Więc jak about:

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

dzięki za powyższych wskazówek, miałem lekką odmianę na zapytania w moim że użytkownik potrzebne wszystkie wartości za poprzedni dzień roboczy. Na przykład dziś jest poniedziałek, więc potrzebuje wszystkiego od ostatniego piątku o północy do soboty o północy. Zrobiłem to za pomocą kombinacji powyższych i "między", jeśli ktoś jest zainteresowany. Nie jestem masowym techie.

-- 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

Możesz łatwo zrobić to wywołanie funkcji, dodając drugi parametr, aby zastąpić GetDate() z dowolną datą. Będzie działać dla dowolnego dnia tygodnia, w dowolnym zakresie dat, jeśli zmienisz GetDate(). Nie zmieni datę jeśli dzień tygodnia jest data wejścia (GetDate())

Declare @DayOfWeek As Integer = 2 -- Monday 

Select DateAdd(Day, ((DatePart(dw,GetDate()) + (7 - @DayOfWeek)) * -1) % 7, Convert(Date,GetDate())) 
Powiązane problemy