简体   繁体   中英

SQL Cursor usage

I'm looking to use a cursor to loop through some customer contract date records to produce a list of all month/years that the customer had within that contract. I'm not even sure if a Cursor is the right solutuion.. But here it is anyway! The topic of Cursors being fairly new to me ..

My data is stored as below;

ContractStartDate   ContractEndDate   CustomerID   Country
01-10-2016          01-02-2017        1234         UK
01-12-2016          01-03-2017        5678         UK

And I'm looking to display it as below;

Customer   Country Month   Year
1234       UK      Oct     2016
1234       UK      Nov     2016
1234       UK      Dec     2016
1234       UK      Jan     2017
1234       UK      Feb     2017
5678       UK      Dec     2016
5678       UK      Jan     2017
5678       UK      Feb     2017
5678       UK      Mar     2017

Script so far below;

DECLARE 

@StartDate  DATETIME,
@EndDate    DATETIME,
@Customer   nvarchar(30),
@Country    nvarchar(30),
@Cursor     as CURSOR;

SET @Cursor = CURSOR FOR
SELECT DISTINCT f.ContractStartDate, f.ContractEndDate, c.Customer, c.Country
FROM Contracts c
    JOIN CustomerInfo i
        ON c.CustomerID = i.ID

OPEN @Cursor
FETCH NEXT FROM @Cursor INTO @StartDate,@EndDate,@Customer,@Country;    

WHILE @@FETCH_STATUS = 0
BEGIN


SELECT  DATENAME(MONTH, DATEADD(MONTH, x.number, @StartDate)) AS MonthName, DATENAME(YEAR, DATEADD(MONTH, x.number, @StartDate)) AS MonthName
FROM    master.dbo.spt_values x
WHERE   x.type = 'P'        
AND     x.number <= DATEDIFF(MONTH, @StartDate, @EndDate);

END

Close @Cursor
DEALLOCATE @Cursor

If you are not heart set on using cursors, here's a different approach.

I've set up a reference calendar, joined to your data, and returned all that sit between the start/end dates. The limit of the way I have done it, is that there is a maximum range of 2048 months ( i limited to 600 here). If you need more, then there are ways to overcome that limitation.

-- Set up for testing

create table test.contracts(
    ContractStartDate datetime,  ContractEndDate datetime,   CustomerID int  ,Country nvarchar(2)
)

insert into test.contracts(ContractStartDate,ContractEndDate,CustomerID,Country) 
Values(convert(datetime,'2016-10-01'), CONVERT(datetime,'2017-02-01'), 1234, 'UK')
insert into test.contracts(ContractStartDate,ContractEndDate,CustomerID,Country) 
Values(convert(datetime,'2016-12-01'), CONVERT(datetime,'2017-03-01'), 5678, 'UK')

-- Execute
SELECT
    C.*, cal.[Month]
FROM test.contracts C
        INNER JOIN 
    (
        SELECT dateadd(m,number,convert(datetime,'2000-01-01')) as [Month]
        FROM master..[spt_values] 
        where type='p' and number BETWEEN 0 AND 600
    ) as cal
    ON C.ContractStartDate <= cal.Month and C.ContractEndDate >= cal.Month

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM