Wybierz COUNT dni między dwiema datami oprócz weekendów


9

Próbuję uzyskać liczbę dni między dwiema różnymi datami, z wyjątkiem weekendów.

Nie wiem, jak osiągnąć ten wynik.


1
Proszę zamieścić strukturę tabeli w celach informacyjnych. Weekendy oznaczają SAT i SŁOŃCE?
Abdul Manaf

Odpowiedzi:


10

Zakładając, że przez „weekend” rozumiesz sobotę i niedzielę , może to być jeszcze prostsze:

SELECT count(*) AS count_days_no_weekend
FROM   generate_series(timestamp '2014-01-01'
                     , timestamp '2014-01-10'
                     , interval  '1 day') the_day
WHERE  extract('ISODOW' FROM the_day) < 6;
  • Nie potrzebujesz dodatkowego poziomu podkwerend dla generate_series(). SRF (zestaw funkcji zwracających), zwany także „funkcjami tabel”, może być używany tak jak tabele w FROMklauzuli.

  • Należy zwrócić uwagę w szczególności, że generate_series() zawiera górną granicę na wyjściu, o ile pasuje pełny przedział (3. parametr). Górna granica jest wykluczona tylko wtedy, gdy ostatni interwał zostanie skrócony, co nie ma miejsca w przypadku pełnych dni.

  • Ze wzorem ISODOWdla EXTRACT () niedziele są zgłaszane jako 7zgodnie ze standardem ISO. Pozwala na prostszy WHEREwarunek.

  • Raczej połączenie generate_series()z timestampwejściem. Oto dlaczego:

  • count(*)jest nieco krótszy i szybszy niż count(the_day), robiąc to samo w tym przypadku.

Aby wykluczyć dolną i / lub górną granicę, odpowiednio dodaj / odejmij 1 dzień. Zazwyczaj możesz dołączyć dolną i wykluczyć górną granicę:

SELECT count(*) AS count_days_no_weekend
FROM   generate_series(timestamp '2014-01-01'
                     , timestamp '2014-01-10' - interval '1 day'
                     , interval '1 day') the_day
WHERE  extract('ISODOW' FROM the_day) < 6;

3

W tym przykładzie wymieniono wszystkie daty między 2013-12-15 a 2014-01-02 (włącznie). Druga kolumna podaje dzień tygodnia (numerycznie, od 0 do 6). Trzecia kolumna wskazuje, czy dniem tygodnia jest sobota / niedziela, czy nie (musisz dostosować to, co uważasz za weekend) i to, co można wykorzystać do zliczania dni tygodnia.

select '2013-12-15'::date + i * interval '1 day',
       extract('dow' from '2013-12-15'::date + i * interval '1 day') as dow,
       case when extract('dow' from '2013-12-15'::date + i * interval '1 day') in (0, 6)
               then false
            else true end as is_weekday
from generate_series(0, '2014-01-02'::date - '2013-12-15'::date) i
;

3

Zakładając, że weekend jest sobota i niedziela, możesz użyć następującego kodu SQL.

select count(the_day) from 
    (select generate_series('2014-01-01'::date, '2014-01-10'::date, '1 day') as the_day) days
where extract('dow' from the_day) not in (0,6)

Zastąp daty swoimi wyborami, a (0,6) dniami tygodnia, które chcesz wykluczyć.

Kilka rzeczy, na które musisz zwrócić uwagę: -

  1. Nie wspominałeś, jaką wersję PostgreSQL używasz. Działa to na wersji 9.1+, ale powinno działać na niższych wersjach.

  2. Wybrane daty są uwzględniane przy korzystaniu z generowania_serwisów. Więc jeśli chcesz dni pomiędzy, dodaj 1 dzień do każdej daty.


0

Jest kilka rzeczy, które możesz zrobić, aby to ułatwić. Metodą, której użyłbym, byłoby upewnienie się, że tabela dat jest dostępna. Możesz szybko utworzyć taki:

CREATE TABLE [dbo].[Dates]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY(0,1),
[Date] Date NOT NULL unique,
isWeekend BIT NOT NULL DEFAULT(0)
)

Po utworzeniu tabeli powinieneś być w stanie stosunkowo szybko zapełnić ją danymi daty.

set datefirst 6 --start date is saturday
INSERT INTO dbo.Dates(Date, isWeekend)
select 
    Date,
    case datepart(weekday,date) 
        --relies on DateFirst being set to 6
        when 2 then 1 
        when 1 then 1
        else 0
    end as isWeekend
from (
    select 
        dateadd(day, number - 1, 0) as date
    from (
        SELECT top 100000 row_number() over (order by o.object_id) as number
        FROM sys.objects o
            cross join sys.objects b
            cross join sys.objects c
    )numbers
)data

Następnie możesz napisać zapytanie jako szybką liczbę rekordów z tej tabeli.

select count(*) as NumberOfWeekDays
from dbo.dates 
where isWeekend = 0
and date between '1 Jan 2013' and '31 Dec 2013'

0

Sugeruję, abyś utworzył funkcję do użycia w dowolnym momencie i pisze mniej; )

Powyższy kod utworzy funkcję sql, która zlicza i zwraca liczbę dni weekendowych (sobota, niedziela). Właśnie w ten sposób będziesz mieć większą elastyczność korzystania z tej funkcji.

CREATE OR REPLACE FUNCTION <YourSchemaNameOptional>.count_full_weekend_days(date, date)
RETURNS bigint AS
$BODY$
        select  COUNT(MySerie.*) as Qtde
        from    (select  CURRENT_DATE + i as Date, EXTRACT(DOW FROM CURRENT_DATE + i) as DiaDate
                 from    generate_series(date ($1) - CURRENT_DATE,  date ($2) - CURRENT_DATE ) i) as MySerie
        WHERE   MySerie.DiaDate in (6,0);
$BODY$
LANGUAGE 'SQL' IMMUTABLE STRICT;

Następnie możesz użyć tej funkcji, aby zwrócić tylko liczbę dni weekendowych w odstępie. Oto przykład do użycia:

SELECT <YourSchemaNameOptional>.count_full_weekend_days('2017-09-11', '2017-09-25') as days; --> RES: 4

Ta selekcja musi zwrócić cztery, ponieważ pierwszy i drugi dzień to poniedziałek, a mamy między nimi 2 soboty i 2 niedziele.

Teraz, aby zwrócić tylko dni robocze (bez weekendów), jak chcesz , po prostu odejmij, jak w poniższym przykładzie:

SELECT (date '2017-09-25' - date '2017-09-11' ) - <YourSchemaName>.count_full_weekend_days('2017-09-11', '2017-09-25'); --> RES: 14 - 4 = 10

-2
-- Returns number of weekdays between two dates
SELECT count(*)  as "numbers of days 
FROM generate_series(0, (‘from_date’::date - 'todate'::date)) i 
WHERE date_part('dow', 'todate'::date + i) NOT IN (0,6)


-- Returns number of weekdays between two dates
SELECT count(*)  as days 
FROM generate_series(0, ('2014/04/30'::date - '2014/04/01'::date)) i 
WHERE date_part('dow', '2014/04/01'::date + i) NOT IN (0,6)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.