Tôi đang cố gắng để có được số ngày giữa hai ngày khác nhau, ngoại trừ cuối tuần.
Tôi không biết làm thế nào để đạt được kết quả này.
Tôi đang cố gắng để có được số ngày giữa hai ngày khác nhau, ngoại trừ cuối tuần.
Tôi không biết làm thế nào để đạt được kết quả này.
Câu trả lời:
Giả sử rằng vào "cuối tuần", bạn có nghĩa là thứ bảy và chủ nhật , điều này có thể đơn giản hơn nữa:
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;
Bạn không cần một cấp độ phụ cho generate_series()
. SRF (thiết lập các hàm trả về), còn được gọi là "các hàm bảng", có thể được sử dụng giống như các bảng trong FROM
mệnh đề.
Đặc biệt lưu ý generate_series()
bao gồm giới hạn trên trong đầu ra, miễn là khoảng thời gian đầy đủ (tham số thứ 3) phù hợp. Giới hạn trên chỉ được loại trừ nếu khoảng thời gian cuối cùng sẽ bị cắt ngắn, đây không phải là trường hợp có đầy đủ ngày.
Với mẫu ISODOW
cho EXTRACT () , Chủ nhật được báo cáo là 7
, theo tiêu chuẩn ISO. Cho phép một WHERE
điều kiện đơn giản hơn .
Thay vì gọi generate_series()
với timestamp
đầu vào. Đây là lý do tại sao:
count(*)
ngắn hơn một chút và nhanh hơn count(the_day)
, làm tương tự trong trường hợp này.
Để loại trừ giới hạn dưới và / hoặc giới hạn trên, hãy thêm / bớt 1 ngày tương ứng. Thông thường, bạn có thể bao gồm giới hạn dưới và loại trừ giới hạn trên:
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;
Ví dụ này liệt kê tất cả các ngày trong khoảng thời gian 2013-12-15 và 2014-01 / 02 (bao gồm). Cột thứ hai cho ngày trong tuần (bằng số, từ 0 đến 6). Cột thứ ba đánh dấu xem ngày trong tuần có phải là Thứ Bảy / Chủ Nhật hay không (bạn sẽ phải điều chỉnh những gì bạn cho là cuối tuần) và là những gì có thể được sử dụng để đếm các ngày trong tuần.
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
;
Giả sử rằng một ngày cuối tuần là thứ bảy và chủ nhật, bạn có thể sử dụng SQL sau.
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)
Thay thế ngày bằng các lựa chọn của bạn và (0,6) bằng các ngày trong tuần bạn muốn loại trừ.
Một vài điều bạn cần lưu ý: -
Bạn chưa đề cập đến phiên bản PostgreSQL nào bạn đang chạy. Điều này hoạt động trên 9.1+ nhưng nên hoạt động trên các phiên bản thấp hơn.
Ngày đã chọn được bao gồm khi sử dụng Gener_series. Vì vậy, nếu bạn muốn ngày ở giữa thì thêm 1 ngày cho mỗi ngày.
Có một vài điều bạn có thể làm để làm điều này dễ dàng hơn. Phương pháp tôi sẽ sử dụng là đảm bảo có sẵn bảng ngày. Bạn có thể nhanh chóng tạo một cái như vậy:
CREATE TABLE [dbo].[Dates]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY(0,1),
[Date] Date NOT NULL unique,
isWeekend BIT NOT NULL DEFAULT(0)
)
Khi bảng được tạo, bạn sẽ có thể điền dữ liệu ngày với dữ liệu ngày tương đối nhanh.
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
Sau đó, bạn có thể viết truy vấn của mình dưới dạng đếm nhanh các bản ghi từ bảng này.
select count(*) as NumberOfWeekDays
from dbo.dates
where isWeekend = 0
and date between '1 Jan 2013' and '31 Dec 2013'
Tôi đề nghị bạn tạo một hàm để sử dụng bất cứ khi nào bạn muốn và viết ít hơn; )
Mã này ở trên sẽ tạo ra một hàm sql đếm và trả về số ngày cuối tuần (Thứ bảy, Chủ nhật). Chỉ là cách bạn sẽ linh hoạt hơn để sử dụng chức năng này.
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;
Sau đó, bạn có thể sử dụng chức năng để chỉ trả về số ngày cuối tuần trong một khoảng. Đây là ví dụ để sử dụng:
SELECT <YourSchemaNameOptional>.count_full_weekend_days('2017-09-11', '2017-09-25') as days; --> RES: 4
Lựa chọn này phải trả lại bốn vì ngày đầu tiên và ngày thứ hai là thứ Hai và chúng tôi có 2 ngày thứ Bảy và 2 Chủ nhật giữa chúng.
Bây giờ, để chỉ trả lại ngày làm việc (không có ngày cuối tuần), như bạn muốn , chỉ cần thực hiện một phép trừ, như ví dụ dưới đây:
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)