2011-01-21 10 views
5

sql sunucusunda İş ilanları için başlangıç ​​ve bitiş tarihlerine sahip bir tablo var. Kullanıcı tarafından bir ay ve bir yıl verildiğinde, o yayın için verilen yıl/aydaki başlangıç ​​ve bitiş tarihleri ​​arasındaki gün miktarını bulmam gerekiyor. gönderme Başlangıç ​​Tarihi 2010/11/15 ve Bitiş Tarihi 2010/12/05 iseBelirli bir yıl/ay içinde bir kayıt için gün sayısını seçme

Yani Sonra çıktı olmalıdır: Ben bu konuda kafamı duvara dayak oldum

November 16 days 
December 5 days 
Total  21 days 

Bir ve fikirlerden taze.

cevap

2

Bu muhtemelen en kısa cevabıdır.

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) 

2048 gün (7-8 yıl) kadar aralıklar için çalışacaktır, ancak gerekirse daha uzun süre uzatılabilir olabilir (sadece istek üzerine - Vasiyet daha karmaşık görünüyor).

convert(char bölümünün tek nedeni, Kasım ayını Aralık ayından önce ve önümüzdeki yılın Ocak ayından önce yapmaktır.

+0

Vay, bazı vahiy! Tabii ki, sistem tablosunu kullanarak kendi yaratma ve doldurma gereğini ortadan kaldırır. Ama benim için en önemli şey gün saymayı seçtiğiniz yol. Korku veren! Ben başkalarının gönderdiği gibi bir sürümü ile geldim, ama şimdi göstermek için utanıyorum: çok önemsiz! –

+0

@Andriy - cevabını bastıysanız hoş olurdu :) – RichardTheKiwi

+0

@cyberwiki: Çok doğru, üzgünüm. Düşündüm de. Bana kendi niyetimi hatırlatmak için çok güzel. :) –

2

Günleri sayacak yukarıda DateDiff

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

d kullanmak istiyorum.

+0

Geçmişi nasıl kullanacağımı biliyorum. Eğer karşılaştırmak için iki tarihim olsaydı, onu kullanırdım. Sorun daha karmaşıktır ve iki örtüşen tarih aralığı içerir. – ChrisOPeterson

+0

@ChirsOPeterson: Sorunuzu tekrar okudum, ama hangi konuyla örtüştüğünüzü anlamadım? Oh bekle, sahip olduğunuz çıktı, nasıl olmasını istersiniz? Öyleyse OMG Ponies veya başka bir site gurusu buna cevap vermek zorunda kalacak çünkü bu noktada emin değilim. – VoodooChild

+0

Yazdığım belirli çıktılar çok önemli değil. Sadece değerleri almam gerek. Örtüşme, İş Başlangıç ​​Tarihi ile Bitiş tarihi arasındaki aralıktan gelir ve her ay Başlangıç ​​Tarihi ve Bitiş tarihi tamamen veya kısmen kısmen olabilir. – ChrisOPeterson

1

DÜZENLEME: Başka küçük bir düzeltme ya da iki ...

Düzenlendi

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

Bu SQL zor biraz öyle ... Tam cevap vermek için ancak bu ay (tam sayı olarak) ve gün sayısı olan bir tablo oluşturur.

Burada aya tamsayı dönüştürmek ve toplam

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

Vay be, bu gerçekten ilginç görünüyor. Teşekkürler! – 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; 

eklemek Ve size bırakacağım aynı anda birçok ile yapmak istediği durumda bir tablo sürümü:

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; 

Orijinal sorgumdan bazı şeyleri basitleştirdim.

+0

Bu da gerçekten harika bir cevap. Gönderdiğiniz için teşekkür ederiz. – ChrisOPeterson

+0

Lütfen, lütfen: Lütfen puanları umursamıyorum, ama eğer reddederseniz, cevabım hakkında yetersiz olan şeylerin bir nebze olsun diye sadece 10 saniye sürdünüz mü? Ben her zaman taktikçe verildiğinde düzeltmeyi, hatta büyük düzeltmeyi sevmek için uğraşıyorum. – ErikE

İlgili konular