Hafta sonları hariç, iki farklı tarih arasındaki gün sayısını almaya çalışıyorum.
Bu sonuca nasıl ulaşacağımı bilmiyorum.
Hafta sonları hariç, iki farklı tarih arasındaki gün sayısını almaya çalışıyorum.
Bu sonuca nasıl ulaşacağımı bilmiyorum.
Yanıtlar:
"Hafta sonu" ile Cumartesi ve Pazar demek istediğinizi varsayarsak , bu daha da basit olabilir:
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;
İçin ek bir alt sorgu seviyesine ihtiyacınız yok generate_series()
. "Tablo işlevleri" olarak da adlandırılan SRF (küme dönen işlevleri), FROM
yan tümcedeki tablolar gibi kullanılabilir .
Özellikle, tam bir aralığa (3. parametre) uyduğu sürece, çıkıştaki üst sınırı generate_series()
içeren not edin . Üst sınır yalnızca son aralık kesilecekse hariç tutulur; bu, tam günlerde geçerli değildir.
EXTRACT () deseniISODOW
ile pazar günleri 7
ISO standardına göre bildirilir . Daha basit bir WHERE
koşul sağlar.
Aksine çağrı generate_series()
ile timestamp
giriş. İşte nedeni:
count(*)
bu durumda biraz daha kısa ve hızlıdır count(the_day)
.
Alt ve / veya üst sınırı hariç tutmak için , buna göre 1 gün ekleyin / çıkarın. Genellikle, alt sınırı ekleyebilir ve üst sınırı hariç tutabilirsiniz:
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;
Bu örnek 2013-12-15 ve 2014-01-02 arasındaki tüm tarihleri (dahil) numaralandırmaktadır. İkinci sütun haftanın gününü verir (sayısal olarak 0 ile 6 arasında). Üçüncü sütun, haftanın gününün Cumartesi / Pazar olup olmadığını belirtir (bir hafta sonu olduğunu düşündüğünüz şeyi uyarlamanız gerekir) ve hafta içi günleri saymak için kullanılabilecek olan şeydir.
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
;
Bir haftasonunun Cumartesi ve Pazar olduğunu varsayarsak, aşağıdaki SQL'i kullanabilirsiniz.
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)
Tarihleri seçeneklerinizle ((0,6) ise hariç tutmak istediğiniz haftanın günleriyle değiştirin.
Dikkat etmeniz gereken birkaç şey: -
Hangi PostgreSQL sürümünü kullandığınızdan bahsetmediniz. Bu 9.1+ sürümünde çalışır ancak daha düşük sürümlerde de çalışması gerekir.
Seçili tarihler create_series kullanılırken kapsayıcıdır. Aradaki günleri istiyorsanız, her tarihe 1 gün ekleyin.
Bunu kolaylaştırmak için yapabileceğiniz birkaç şey var. Kullanacağım yöntem bir tarih tablosunun mevcut olduğundan emin olmak olacaktır. Hızlı bir şekilde aşağıdakini oluşturabilirsiniz:
CREATE TABLE [dbo].[Dates]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY(0,1),
[Date] Date NOT NULL unique,
isWeekend BIT NOT NULL DEFAULT(0)
)
Tablo oluşturulduktan sonra, tabloyu tarih verileriyle nispeten hızlı bir şekilde doldurabilmeniz gerekir.
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
Daha sonra sorgunuzu bu tablodan hızlı bir kayıt sayısı olarak yazabilirsiniz.
select count(*) as NumberOfWeekDays
from dbo.dates
where isWeekend = 0
and date between '1 Jan 2013' and '31 Dec 2013'
İstediğiniz zaman kullanmak için bir işlev oluşturmanızı ve daha az yazmanızı öneririm; )
Yukarıdaki bu kod, hafta sonu günlerinin sayısını (Sat, Sun) sayan ve döndüren bir sql işlevi oluşturur. Tam da bu işlevi kullanma esnekliğiniz olacaktır.
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;
Bundan sonra, işlevi yalnızca aralıklı olarak hafta sonu günlerinin sayısını döndürmek için kullanabilirsiniz . Kullanılacak örnek:
SELECT <YourSchemaNameOptional>.count_full_weekend_days('2017-09-11', '2017-09-25') as days; --> RES: 4
Bu seçim dördü geri getirmeli çünkü birinci ve ikinci gün Pazartesi ve aralarında 2 Cumartesi ve 2 Pazar var.
Şimdi, yalnızca iş günlerini (hafta sonları olmadan) istediğiniz gibi döndürmek için , aşağıdaki örnek gibi bir çıkarma yapın:
SELECT (date '2017-09-25' - date '2017-09-11' ) - <YourSchemaName>.count_full_weekend_days('2017-09-11', '2017-09-25'); --> RES: 14 - 4 = 10
-- 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)