2011-01-21 25 views
5

Trong máy chủ sql Tôi có một bảng có ngày bắt đầu và ngày kết thúc cho các bài đăng công việc. Được một tháng và một năm bởi người dùng, tôi cần phải tìm số ngày giữa ngày bắt đầu và ngày kết thúc rơi vào năm/tháng nhất định cho bài đăng đó.Chọn số ngày mà một bản ghi có mặt trong một năm/tháng

Vì vậy, nếu ngày niêm yết bắt đầu là 2010/11/15 và ngày kết thúc là 2010/12/05 Sau đó, sản lượng nên là:

November 16 days 
December 5 days 
Total  21 days 

Tôi đã đập đầu tôi vào tường với điều này một ý tưởng mới mẻ.

Trả lời

2

Đây có lẽ là câu trả lời ngắn gọn nhất.

declare @start datetime, @end datetime 
select @start = '20101115', @end = '20101205' 

select datename(month,@start+number), count(*) 
from master..spt_values 
where type='P' 
    and number between 0 and datediff(d,@start,@end) 
group by datename(month,@start+number), convert(char(6),@start+number,112) 
order by convert(char(6),@start+number,112) 

Nó sẽ hoạt động trong phạm vi tối đa 2048 ngày (7-8 năm) nhưng có thể kéo dài lâu hơn nếu bạn cần (theo yêu cầu - trông sẽ phức tạp hơn).

Lý do duy nhất cho phần convert(char là đưa tháng 11 đến trước tháng 12 và cũng trước tháng 1 của năm tiếp theo.

+0

Chà, một số điều mặc khải! Tất nhiên, việc sử dụng bảng hệ thống sẽ phụ thuộc vào nhu cầu tạo và điền vào bảng của chúng ta. Nhưng điều chính đối với tôi ở đây là cách bạn đã chọn để đếm ngày. Tuyệt vời! Tôi đã đưa ra một phiên bản giống như những gì người khác đã đăng, nhưng bây giờ tôi xấu hổ để hiển thị nó: quá tầm thường! –

+0

@Andriy - sẽ rất tuyệt nếu bạn upvoted câu trả lời :) – RichardTheKiwi

+0

@cyberwiki: Rất đúng, xin lỗi. Nghĩ rằng tôi đã upvoted nó. Rất tốt đẹp của bạn để nhắc nhở tôi về ý định của riêng tôi. :) –

2

Bạn muốn sử dụng DateDiff

DateDiff("d",[StartDate],[EndDate])

các d trên sẽ đếm ngày.

+0

Tôi biết cách sử dụng dateiff. Nếu tôi có hai ngày để so sánh thì tôi sẽ sử dụng nó. Vấn đề phức tạp hơn và liên quan đến hai khoảng thời gian chồng chéo nhau. – ChrisOPeterson

+0

@ChirsOPeterson: Tôi chỉ đọc lại câu hỏi của bạn, nhưng tôi không thấy những gì chồng chéo bạn nói đến? Oh chờ đợi, đầu ra bạn có, là làm thế nào bạn muốn nó? Nếu đó là OMG Ponies hoặc một số chuyên gia trang web khác sẽ phải trả lời rằng bởi vì tôi không chắc chắn vào thời điểm này. – VoodooChild

+0

Đầu ra cụ thể mà tôi đã viết không quá quan trọng. Tôi chỉ cần nhận được các giá trị. Chồng chéo xuất phát từ khoảng thời gian giữa Ngày bắt đầu công việc và Ngày kết thúc và sau đó mỗi tháng bắt đầu ngày và ngày kết thúc có thể hoàn toàn hoặc chỉ một phần là một phần của. – ChrisOPeterson

0

Ví dụ sau đây sẽ quyết định sự khác biệt trong những ngày giữa ngày hiện tại và ngày đặt hàng cho các sản phẩm trong cơ sở dữ liệu AdventureWorks.

USE AdventureWorks; 
GO 
SELECT DATEDIFF(day, OrderDate, GETDATE()) AS NumberOfDays 
FROM Sales.SalesOrderHeader; 
GO 

http://msdn.microsoft.com/en-us/library/ms189794%28v=sql.90%29.aspx

1

EDIT: Một hoặc sửa chữa nhỏ hai ...

Edited để cung cấp cho câu trả lời đầy đủ ...

declare @user_start_date datetime 
set @user_start_date = '1/1/2011' 
declare @user_end_date datetime 
set @user_end_date = '1/10/2011' 
declare @job_start_date datetime 
set @job_start_date = '1/2/2011' 
declare @job_end_date datetime 
set @job_end_date = '1/11/2011' 

declare @nextStartDate datetime; 
set @nextStartDate = str(datepart(mm, @user_start_date)) + '/1/' + str(datepart(yyyy, @user_start_date)) 
declare @nextEndDate datetime; 
set @nextEndDate = dateadd(dd,-1,dateadd(mm,1,@nextStartDate)) 

create table #monthYears(startDate datetime, endDate datetime) 
while (@nextStartDate < @user_end_date) begin 
    insert into #monthYears values(@nextStartDate, @nextEndDate) 
    set @nextStartDate = dateadd(mm,1,@nextStartDate) 
    set @nextEndDate = dateadd(dd,-1,dateadd(mm,1,@nextStartDate)) 
end 

-- Print Months 
select [month], [year], case when dayCount < 0 then 0 else dayCount end from (
select month(startDate) month, year(startDate) year , datediff(dd, 
    case when startDate > @job_start_date then startDate else @job_start_date end, 
    case when endDate < @job_end_date then endDate else @job_end_date end) dayCount 
from #monthYears) temp 

select datediff(dd, 
    case when @user_start_date > @job_start_date then @user_start_date else @job_start_date end, 
    case when @user_end_date < @job_end_date then @user_end_date else @job_end_date end) 
1

Đây là kinda cứng trong SQL nhưng điều này sẽ tạo ra một bảng với tháng (trong số nguyên) và số ngày.

Tôi sẽ để lại nó cho bạn để chuyển đổi số nguyên để tháng và thêm tổng

SET NOCOUNT on 

Declare @StartDate datetime 
Declare @EndDate datetime 
Declare @StartDateNormalized datetime 
Declare @EndDateNormalized datetime 


SET @StartDate = '2010/11/15' 
SET @EndDate = '2011/2/05' 

declare @result table (month int, days int) 


--Normalize the Inputs 

SET @StartDateNormalized = cast(Month(@startDate) as varchar) + '/1/' + cast(year(@startDate) as varchar) 
SET @EndDateNormalized = cast(Month(@EndDate) as varchar) + '/1/' + cast(year(@EndDate) as varchar) 

insert into @result 
values 
( MONTH(@StartDateNormalized), 
    DateDiff(Day, @StartDate, DateAdd(month, 1, @StartDateNormalized)) 
) 

SET @StartDateNormalized = DateAdd(month, 1, @StartDateNormalized) 

WHILE (@StartDateNormalized < @EndDateNormalized) 
BEGIN 

insert into @result 
values 
( MONTH(@StartDateNormalized), 
    DateDiff(Day, @StartDateNormalized, DateAdd(month, 1, @StartDateNormalized)) 
) 

    SET @StartDateNormalized = DateAdd(month, 1, @StartDateNormalized) 
END 

insert into @result 
values 
( MONTH(@EndDateNormalized), 
    DateDiff(Day, @EndDateNormalized, @EndDate ) + 1 
) 


select * from @result 
+0

Cái này trông rất thú vị. Cảm ơn! – ChrisOPeterson

1
DECLARE 
    @StartDate datetime, 
    @EndDate datetime; 
SET @StartDate = '20101115'; 
SET @EndDate = '20101205'; 

WITH Mos AS (
    SELECT 
     Number, 
     DateAdd(Month, Number, @StartDate - Day(@StartDate) + 1) MoDate 
    FROM master.dbo.spt_values 
    WHERE 
     Type = 'P' 
     AND Number <= DateDiff(Month, @StartDate, @EndDate) 
), Dys AS (
    SELECT 
     MoDate, 
     DateDiff(
     Day, 
     CASE WHEN Number = 0 THEN @StartDate ELSE MoDate END, 
     CASE WHEN Number = DateDiff(Month, @StartDate, @EndDate) THEN @EndDate ELSE DateAdd(Month, 1, MoDate) - 1 END 
    ) + 1 Cnt 
    FROM Mos 
) 
SELECT 
    Year(MoDate) Yr, 
    Coalesce(DateName(Month, MoDate), 'Total') Mo, 
    Convert(varchar(11), Sum(Cnt)) + ' day' + CASE WHEN Sum(Cnt) = 1 THEN '' ELSE 's' END Descr 
FROM Dys 
GROUP BY MoDate 
WITH ROLLUP 
ORDER BY Grouping(MoDate), MoDate; 

Và đây là một phiên bản bảng trong trường hợp bạn muốn làm điều đó với nhiều cùng một lúc:

CREATE TABLE AccountDates (
    AccountCode varchar(10) NOT NULL CONSTRAINT PK_AccountDates PRIMARY KEY CLUSTERED, 
    StartDate datetime, 
    EndDate datetime 
); 

INSERT AccountDates VALUES ('BLINKEN', '20101115', '20101205'); 
INSERT AccountDates VALUES ('KRAM', '20101027', '20110118'); 
INSERT AccountDates VALUES ('NUVU', '20101207', '20101207'); 

WITH Mos AS (
    SELECT 
     AccountCode, 
     D.StartDate, 
     D.EndDate, 
     Number, 
     DateAdd(Month, Number, D.StartDate - Day(D.StartDate) + 1) MoDate 
    FROM 
     AccountDates D 
     INNER JOIN master.dbo.spt_values V ON V.Number <= DateDiff(Month, D.StartDate, D.EndDate) 
    WHERE 
     V.Type = 'P' 
), Dys AS (
    SELECT 
     AccountCode, 
     MoDate, 
     DateDiff(
     Day, 
     CASE WHEN Number = 0 THEN StartDate ELSE MoDate END, 
     CASE WHEN Number = DateDiff(Month, StartDate, EndDate) THEN EndDate ELSE DateAdd(Month, 1, MoDate) - 1 END 
    ) + 1 Cnt 
    FROM Mos 
) 
SELECT 
    AccountCode, 
    Year(MoDate) Yr, 
    Coalesce(DateName(Month, MoDate), 'Total') Mo, 
    Convert(varchar(11), Sum(Cnt)) + ' day' + CASE WHEN Sum(Cnt) = 1 THEN '' ELSE 's' END Descr 
FROM Dys 
GROUP BY AccountCode, MoDate 
WITH ROLLUP 
HAVING Grouping(AccountCode) = 0 
ORDER BY 
    AccountCode, 
    Grouping(MoDate), 
    MoDate; 

Tôi đã đơn giản hoá mọi thứ một chút so với truy vấn ban đầu của mình.

+0

Đây cũng là một câu trả lời rất hay. Cảm ơn bạn đã gửi. – ChrisOPeterson

+0

Xin vui lòng, xin vui lòng, xin vui lòng: Tôi không quan tâm về các điểm, nhưng nếu bạn downvote, bạn sẽ chỉ mất 10 giây để cho tôi một inkling của những gì đã không đạt yêu cầu về câu trả lời của tôi? Tôi luôn phấn đấu để cải thiện và yêu thích sự điều chỉnh, thậm chí là điều chỉnh chính, khi được đưa ra một cách khéo léo. – ErikE

Các vấn đề liên quan