J'essaie d'obtenir le nombre de jours entre deux dates différentes, sauf les week-ends.
Je ne sais pas comment obtenir ce résultat.
En supposant que par "week-end" vous voulez dire samedi et dimanche, cela peut être encore plus simple:
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;
Vous n'avez pas besoin d'un niveau de sous-requête supplémentaire pour generate_series()
. SRF (set return functions), également appelé "table-fonctions", peut être utilisé comme les tables de la clause FROM
.
Notez en particulier que generate_series()
inclut la limite supérieure dans la sortie, tant qu'un complet = intervalle (3e paramètre) correspond. La limite supérieure n'est exclue que si le dernier intervalle est tronqué, ce qui n'est pas le cas pour les jours entiers.
Avec le modèle ISODOW
pour EXTRACT () , les dimanches sont signalés comme 7
, Selon la norme ISO. Permet une condition WHERE
plus simple.
Appelez plutôt generate_series()
avec timestamp
entrée. Voici pourquoi:
count(*)
est légèrement plus court et plus rapide que count(the_day)
, faisant de même dans ce cas.
Pour exclure borne inférieure et/ou supérieure, ajoutez/soustrayez 1 jour en conséquence. En règle générale, vous pouvez inclure la limite inférieure et exclure la limite supérieure:
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;
Cet exemple énumère toutes les dates entre le 2013-12-15 et le 2014-01-02 (inclusivement). La deuxième colonne donne le jour de la semaine (numériquement, entre 0 et 6). La troisième colonne indique si le jour de la semaine est un samedi/dimanche ou non (vous devrez adapter ce que vous considérez comme un week-end) et c'est ce qui pourrait être utilisé pour compter les jours de la semaine.
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
;
En supposant qu'un week-end est le samedi et le dimanche, vous pouvez utiliser le SQL suivant.
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)
Remplacez les dates par vos choix et le (0,6) par les jours de la semaine que vous souhaitez exclure.
Quelques points dont vous devez prendre note: -
Vous n'avez pas mentionné la version de PostgreSQL que vous utilisez. Cela fonctionne sur 9.1+ mais devrait fonctionner sur les versions inférieures.
Les dates choisies sont incluses lors de l'utilisation de generate_series. Donc, si vous voulez des jours entre les deux, ajoutez 1 jour à chaque date.
Il y a deux ou trois choses que vous pouvez faire pour rendre cela plus facile. La méthode que j'utiliserais serait de s'assurer qu'un tableau des dates est disponible. Vous pouvez rapidement en créer un comme ceci:
CREATE TABLE [dbo].[Dates]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY(0,1),
[Date] Date NOT NULL unique,
isWeekend BIT NOT NULL DEFAULT(0)
)
Une fois le tableau créé, vous devriez pouvoir le remplir avec des données de date relativement rapidement.
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
Vous pouvez ensuite écrire votre requête sous la forme d'un décompte rapide des enregistrements de cette table.
select count(*) as NumberOfWeekDays
from dbo.dates
where isWeekend = 0
and date between '1 Jan 2013' and '31 Dec 2013'
Je vous suggère de créer une fonction à utiliser quand vous le souhaitez et d'écrire moins; )
Ce code ci-dessus créera une fonction sql qui compte et renvoie le nombre de jours de week-end (samedi, dimanche). Tout comme vous aurez plus de flexibilité pour utiliser cette fonction.
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;
Après cela, vous pouvez utiliser la fonction pour renvoyer uniquement le nombre de jours de week-end dans un intervalle. Voici l'exemple à utiliser:
SELECT <YourSchemaNameOptional>.count_full_weekend_days('2017-09-11', '2017-09-25') as days; --> RES: 4
Cette sélection doit renvoyer quatre car le premier et le deuxième jour sont lundi, et nous avons 2 samedis et 2 dimanches entre eux.
Maintenant, pour ne renvoyer que les jours ouvrables (sans week-end), comme vous le souhaitez , faites simplement une soustraction, comme dans l'exemple ci-dessous :
SELECT (date '2017-09-25' - date '2017-09-11' ) - <YourSchemaName>.count_full_weekend_days('2017-09-11', '2017-09-25'); --> RES: 14 - 4 = 10