SQL Server : multi-part identifier could not be bound - sql

I need a simple output of fields named "36" - "1" with the extended inventory value for everything in the specified item classes. I don't need itemization.
E.g.
Error is:
"Database Connector Error. '42000:[Microsoft][ODBC SQL Server Driver][SQL Server]The multi-part identifier "InvenFiscPerHistTable.FiscalPeriod" could no be bound. [Database Vendor Code: 4104 ]'
Here's my SQL.
DECLARE #CalMonth INT
DECLARE #CalYear INT
DECLARE #CalMoYear DATETIME
SET #CalMonth = CASE WHEN "InvenFiscPerHistTable"."FiscalPeriod" IN (1,2,3) THEN "InvenFiscPerHistTable"."FiscalPeriod" + 9 ELSE "InvenFiscPerHistTable"."FiscalPeriod" - 3 END
SET #CalYear = CASE WHEN "InvenFiscPerHistTable"."FiscalPeriod" IN (1,2,3) THEN "InvenFiscPerHistTable"."FiscalYear" + 1 ELSE "InvenFiscPerHistTable"."FiscalYear" END
SET #CalMoYear = CAST(CONVERT(NVARCHAR, #CalYear) + '-' + CONVERT(NVARCHAR, #CalMonth) + '-' + CONVERT(NVARCHAR,1) AS DATETIME)
--our fiscal year is not the same as the calendar year
--e.g. FiscalPeriod = 1 and FiscalYear = 2016 will be October 2015
SELECT SUM (CASE WHEN #CalMoYear BETWEEN DATEADD(m, -36, GETDATE()-day(GETDATE()-1)) AND DATEADD(m, -35, GETDATE()-day (GETDATE()-1))-1 THEN"InvenFiscPerHistTable"."QOH" * "InvenTable"."UnitCost" ELSE NULL END) AS "36"
,SUM (CASE WHEN #CalMoYear BETWEEN DATEADD(m, -35, GETDATE()-day(GETDATE()-1)) AND DATEADD(m, -34, GETDATE()-day (GETDATE()-1))-1 THEN"InvenFiscPerHistTable"."QOH" * "InvenTable"."UnitCost" ELSE NULL END) AS "35"
,SUM (CASE WHEN #CalMoYear BETWEEN DATEADD(m, -34, GETDATE()-day(GETDATE()-1)) AND DATEADD(m, -33, GETDATE()-day (GETDATE()-1))-1 THEN"InvenFiscPerHistTable"."QOH" * "InvenTable"."UnitCost" ELSE NULL END) AS "34"
--and so on until I have 36 months of history up through last month
FROM "InvenTable"
INNER JOIN "SKUTable" ON "InvenTable"."SKUKey" = "SKUTable"."SKUKey"
INNER JOIN "InvenFiscPerHistTable" ON ("InvenTable"."SKUKey" = "InvenFiscPerHistTable"."SKUKey")
AND ("InvenTable"."WarehouseKey" = "InvenFiscPerHistTable"."WarehouseKey")
INNER JOIN "SKUClassTable" "SKUClassTable" ON "SKUTable"."ICKey" = "SKUClassTable"."ICKey"
WHERE "SKUClassTable"."ItemClassName" IN (
'105-03'
,'105-04'
,'105-05'
,'105-06'
,'150-01'
)

I played around a bit with your query and think it can be rewritten and simplified (in my opinion) to the query below. The only thing you need to do is add more items in the pivot part at the end to get more columns.
The logic is that it calculates the difference in months between the first day of the current month and the date that is created from the FiscalYear and FiscalPeriod (according to your rules).
I believe it should work, unless I missed something vital, but without any test data there's of course a fair amount of guess work involved ;-)
Please give it a try and if it doesn't work I'll remove my answer.
I formatted it a bit less compact than it could be to make it easier to follow.
;WITH CTE AS
(
SELECT
SKUKey, WarehouseKey, FiscalPeriod, FiscalYear, QOH,
diff = DATEDIFF
(
month,
CASE WHEN FiscalPeriod IN (1,2,3)
THEN
CAST(FiscalYear + 1 AS CHAR(4))
+ '-' + CAST(FiscalPeriod + 9 AS VARCHAR(2))
+ '-' + CAST(1 AS CHAR(1))
ELSE
CAST(FiscalYear AS CHAR(4))
+ '-' + CAST(FiscalPeriod - 3 AS VARCHAR(2))
+ '-' + CAST(1 AS CHAR(1))
END,
DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
)
FROM InvenFiscPerHistTable
)
SELECT * FROM
(
SELECT diff, QOH * UnitCost as TotalCost
FROM InvenTable i
INNER JOIN SKUTable s ON i.SKUKey = s.SKUKey
INNER JOIN cte ON (i.SKUKey = cte.SKUKey) AND (i.WarehouseKey = cte.WarehouseKey)
INNER JOIN SKUClassTable sc ON s.ICKey = sc.ICKey
WHERE sc.ItemClassName IN ('105-03','105-04','105-05','105-06','150-01')
) A
PIVOT ( SUM(TotalCost) FOR diff IN ([36],[35],[2],[1]) ) p -- add more columns here

Related

SQL calculations not returning the expected values

I've taken over a project from a different developer. This developer favoured working in SQL over C# code, however I am admittedly not very strong with SQL and am having trouble fixing a bug in the project.
A holiday system exists in this project. Each user has the following:
Entitled holidays
Holiday taken
Lieu/adjusted holidays
Holiday brought forward
A remaining holiday value is then calculated which takes the above values and generates a result.
For example, Person A has:
20 entitled
7.5 taken
3 in lieu
2 brought forward
The expected result would be 17.5 remaining ((20 + 3 + 2) - 7.5) however the result given from the existing stored procedure for the above example is 22
Another user has the following:
25 entitled
1 taken
2 in lieu
5 brought forward
This user is seeing 30 instead of the expected 31
Since each individual value for the above seems to working, it points to the calculation of the total remaining holiday that's not working. Here is the current procedure for calculating this value:
DECLARE #USER_HOLIDAYS decimal(18,2)
DECLARE #LieuAdjustedHolidays decimal(18,2)
DECLARE #Total_Holidays decimal(18,2)
DECLARE #Remain_Holidays decimal(18,2)
SELECT #USER_HOLIDAYS = SUM(HolidayEntitlement + HolidaysBroghtForward)
FROM cms_user
WHERE UserID = #UserID
SELECT
#LieuAdjustedHolidays = CASE
WHEN SUM(Duration) IS NULL
THEN 0
ELSE SUM(Duration)
END
FROM
No6_LieuAdjustedHolidays
WHERE
UserID = #UserID
AND ItemCreatedWhen >= '' + CAST(DATEPART(yy, GETDATE()) AS VARCHAR(100)) + ' -11-01'
SET #Total_Holidays = SUM(#USER_HOLIDAYS + CASE WHEN #LieuAdjustedHolidays IS NULL THEN 0 ELSE #LieuAdjustedHolidays END )
SELECT
#Remain_Holidays = #Total_Holidays - CASE WHEN SUM(Duration) IS NULL THEN 0 ELSE SUM(Duration) END
FROM
No6_Holidays
WHERE
ItemCreatedby = #UserID
AND status = 'Accepted'
AND StartDate >= '' + CAST(DATEPART(yy, GETDATE()) AS VARCHAR(100)) + ' -11-01'
AND EndDate <= '' + CAST(DATEPART(yy, DATEADD(YEAR, 1, GETDATE())) AS VARCHAR(100)) + '-10-31'
UPDATE cms_user
SET RemainingHolidays = #Remain_Holidays
WHERE UserID = #UserID
SELECT
#Total_Holidays - CASE WHEN SUM(Duration) IS NULL THEN 0 ELSE SUM(Duration) END
FROM
No6_Holidays
WHERE
ItemCreatedby = #UserID
AND status = 'Accepted'
AND StartDate >= '' + CAST(DATEPART(yy, GETDATE()) AS VARCHAR(100)) + ' -11-01'
AND EndDate <= '' + CAST(DATEPART(yy, DATEADD(YEAR, 1, GETDATE())) AS VARCHAR(100)) + '-10-31'
With this part being the section that I don't believe is calculating correctly:
SELECT #Total_Holidays - CASE WHEN SUM(Duration) IS NULL THEN 0 ELSE SUM(Duration) END FROM No6_Holidays
WHERE ItemCreatedby = #UserID and status = 'Accepted' and StartDate >= '' + cast(DATEPART(yy, GETDATE()) as varchar(100)) + ' -11-01'
and EndDate <= '' + cast(DATEPART(yy, DATEADD(YEAR, 1, GETDATE())) as varchar(100)) + '-10-31'
Since I have a very limited understanding of SQL I'm struggling to understand what's going wrong here. Is anyone able to help?
Thanks in advance

Get Last date of month SQL

I need to find the last day of a month in the american (mm-dd-yyyy) format for a column which has yymm(nvarchar format).
example:- for 1601---> 01-31-2016
Thank you for help!
Using convert to get the date of the 1st of the month, then dateadd to get the next month, and one more dateadd to get one day before:
DECLARE #D char(4) = '1601'
SELECT DATEADD(DAY, -1, DATEADD(MONTH, 1, CONVERT(date, #D + '01', 12)))
Result:
2016-01-31
With a string of 1601, we just need to append a 01 because the century will be assumed. This new string of 160101 can be converted into a date.
Example
select convert(varchar(10),dateadd(day,-1,dateadd(month,1,YourCol+'01')),101)
From YourTable
Returns
01/31/2016
Since you said year 20XX...
declare #oddDate nvarchar(4) = '1601'
select
DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, '20' + cast(YY as varchar(2)) + cast(MM as varchar(2)) + '01') + 1, 0)) as LastDayof20Year
,'20' + cast(YY as varchar(2)) + cast(MM as varchar(2)) + '01' as MadeUpDate
from
(select
left(#oddDate,2) as YY
,right(#oddDate,2) as MM) x
Or simply...
select
DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, '20' + cast(left(#oddDate,2) as varchar(2)) + cast(right(#oddDate,2) as varchar(2)) + '01') + 1, 0)) as LastDayof20Year
Something like the following should do the trick...
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL
DROP TABLE #TestData;
CREATE TABLE #TestData (
CharDate CHAR(4) NOT NULL
);
INSERT #TestData (CharDate) VALUES
('9801'), ('9902'), ('0012'), ('0202'), ('1005'), ('1503');
--============================================================
SELECT
FormattedEOM = CONVERT(CHAR(10), em.EndOfMonth, 101)
FROM
#TestData td
CROSS APPLY ( VALUES (CASE WHEN CAST(LEFT(td.CharDate, 2) AS INT) > 30 THEN '19' ELSE '20' END) ) c (Century)
CROSS APPLY ( VALUES (DATEFROMPARTS(CONCAT(c.Century, LEFT(td.CharDate, 2)), RIGHT(td.CharDate, 2), 1)) ) fm (FirstOfMonth)
CROSS APPLY ( VALUES (EOMONTH(fm.FirstOfMonth)) ) em (EndOfMonth);
HTH,
Jason
Edit: The following should work with 2008....
SELECT
FormattedEOM = CONVERT(CHAR(10), em.EndOfMonth, 101)
FROM
#TestData td
CROSS APPLY ( VALUES (CASE WHEN CAST(LEFT(td.CharDate, 2) AS INT) > 30 THEN '19' ELSE '20' END) ) c (Century)
CROSS APPLY ( VALUES (CAST(c.Century + td.CharDate + '01' AS DATE)) ) fm (FirstOfMonth)
CROSS APPLY ( VALUES (DATEADD(mm, 1, fm.FirstOfMonth)) ) nm (NextMonth)
CROSS APPLY ( VALUES (DATEADD(dd, -1, nm.NextMonth)) ) em (EndOfMonth);

Need monthly report where I need summation of Qty for each day

I have one table STOCK_REGISTER where I have columns Id, ItmId, Qty, CreatedDate. And there are daily transaction data like item inward, outward and all.
Now I am developing one Monthly Report where I want to display Day wise summation of item qty for whole month. I have written following query to do so.
SELECT CONVERT(Date,CreatedDate) AS CreatedDate,ItmId, SUM(Qty)
FROM STOCK_REGISTER
GROUP BY CONVERT(Date,CreatedDate),ItmId
This query returns correct data but if I am asking for April-2017 data and STOCK_REGISTER don't have any record on 5th April then it's not displaying 5th April at all where I need 0 value in qty for that item in 5th April.
Can you help me out to get this type of data?
Edit :
I have created query which gives all days of any particular month and have applied left join with STOCK_REGISTER, but still not solving my issue.
declare #month int, #year int
set #month = 4
set #year = 2017
SELECT CAST(CAST(#year AS VARCHAR) + '-' + CAST(#Month AS VARCHAR) + '-01' AS DATETIME) + A.Number AS STKFG_CREATED_DATE,
B.STKFG_ITM_ID,
0 AS OPENING_STOCK,
SUM(STKFG_QTY)
FROM master..spt_values A
LEFT JOIN STOCK_REGISTER_FG B
ON CONVERT(DATE,CAST(CAST(#year AS VARCHAR) + '-' + CAST(#Month AS VARCHAR) + '-01' AS DATETIME) + A.Number) = CONVERT(DATE,B.STKFG_CREATED_DATE)
AND C.ITM_ID = B.STKFG_ITM_ID
WHERE type = 'P'
AND (CAST(CAST(#year AS VARCHAR) + '-' + CAST(#Month AS VARCHAR) + '-01' AS DATETIME) + A.Number ) <
DATEADD(mm,1,CAST(CAST(#year AS VARCHAR) + '-' + CAST(#Month AS VARCHAR) + '-01' AS DATETIME) )
AND STKFG_TRAT_ID = 6
GROUP BY A.Number, B.STKFG_ITM_ID
ORDER BY B.STKFG_ITM_ID,CAST(CAST(#year AS VARCHAR) + '-' + CAST(#Month AS VARCHAR) + '-01' AS DATETIME) + A.Number
Thank you for your comments.
I have found one solution which works fine for me.
Here #TEMP_TABLE contains all dates.
SELECT A.CREATED_DATE,B.ITM_NAME,ISNULL(C.STKFG_QTY,0)
FROM #TEMP_TABLE A
CROSS APPLY ITEM_MASTER B
LEFT JOIN ( SELECT CONVERT(DATE,STKFG_CREATED_DATE) AS STKFG_CREATED_DATE, STKFG_ITM_ID, SUM(STKFG_QTY) AS STKFG_QTY
FROM STOCK_REGISTER_FG GROUP BY CONVERT(DATE,STKFG_CREATED_DATE),STKFG_ITM_ID) C
ON CONVERT(DATE,A.CREATED_DATE) = CONVERT(DATE,C.STKFG_CREATED_DATE)
AND B.ITM_ID = C.STKFG_ITM_ID
ORDER BY B.ITM_NAME,A.CREATED_DATE
Try below script. Here #tblData is your actual table name.
declare #tblData table
(id int,datecolumn date)
INSERT INTO #tblData
(id,datecolumn)
SELECT 1,'2010-01-01' UNION ALL
SELECT 3,'2010-01-01' UNION ALL
SELECT 1,'2010-01-03' UNION ALL
SELECT 2,'2010-01-04' UNION ALL
SELECT 1,'2010-01-05' UNION ALL
SELECT 3,'2010-01-06' UNION ALL
SELECT 1,'2010-01-10' UNION ALL
SELECT 1,'2010-01-10' UNION ALL
SELECT 2,'2010-01-11' UNION ALL
SELECT 1,'2010-01-11' UNION ALL
SELECT 2,'2010-01-11' UNION ALL
SELECT 1,'2010-01-12' UNION ALL
SELECT 3,'2010-01-13'
DECLARE #MaxDate DATE,
#MinDate DATE,
#iDate DATE
DECLARE #DateSequence TABLE(
DATE1 DATE
)
SELECT #MaxDate = Convert(DATE,Max(datecolumn)),
#MinDate = Convert(DATE,Min(datecolumn))
FROM #tblData -- Put your month condition
SET #iDate = #MinDate
WHILE (#iDate <= #MaxDate)
BEGIN
INSERT #DateSequence
SELECT #iDate
SET #iDate = Convert(DATE,Dateadd(DAY,1,#iDate))
END
SELECT a.DATE1 ,isnull(sum(b.id),0) as total
FROM #DateSequence a left join #tblData b on a.DATE1=b.datecolumn
group by a.DATE1
Thanks,

PIVOT SQL Data & Fill In Blanks

I'm attempting to transform this data:
ItemID MonthAsInt Month Year InvType Quantity
4643 4 April 2011 Shipment 10
4643 5 May 2011 Shipment 10
4643 7 July 2011 Shipment 10
4643 8 August 2011 Destroy 10
4643 11 November 2011 Shipment 25
4643 12 December 2011 Picking 1
Into this (basically, a 12 month snap shot):
February March April May June July August ...
Shipment 0 0 10 10 0 10 0
Picking 0 0 0 0 0 0 0
Destroy ...
I've messed with the PIVIOT method, but I haven't had much luck. At this point, all I have is the list of dates that I need between GETDATE() and GETDATE() - 12 months (retrieved with the query below):
DECLARE #BeginDate DATETIME
DECLARE #EndDate DATETIME
SET #BeginDate = GETDATE();
SET #EndDate = DATEADD(MONTH, -12, GETDATE());
WITH CTE_DatesTable
AS
(
SELECT #EndDate AS [Date]
UNION ALL
SELECT DATEADD(dd, 1, [date])
FROM CTE_DatesTable
WHERE DATEADD(dd, 1, [date]) <= #BeginDate
)
SELECT DISTINCT DATENAME(MONTH, [date]) + ' '
+ CAST(YEAR([date]) AS VARCHAR(4)) AS MonthYear,
YEAR([date]) AS YearAsInt,
MONTH([Date]) AS MonthAsInt
FROM CTE_DatesTable
ORDER BY YEAR([date]), MONTH([Date])
OPTION (MAXRECURSION 0)
See the query in action here.
Is what I'm trying to accomplish possible? Am I going in the right direction? Any help would be appreciated!
You can do this without pivot (the syntax for which I find daunting as well). Since you don't know the actual layout of columns beforehand, I think this is easiest with dynamic SQL. Given the following table/sample data:
USE tempdb;
GO
CREATE TABLE dbo.foo
(
ItemID INT,
MonthAsInt INT,
[Month] VARCHAR(12),
[Year] INT,
InvType VARCHAR(12),
Quantity INT
);
INSERT dbo.foo SELECT 4643,4 ,'April ',2011,'Shipment',10
UNION ALL SELECT 4643,5 ,'May ',2011,'Shipment',10
UNION ALL SELECT 4643,7 ,'July ',2011,'Shipment',10
UNION ALL SELECT 4643,8 ,'August ',2011,'Destroy ',10
UNION ALL SELECT 4643,11,'November',2011,'Shipment',25
UNION ALL SELECT 4643,12,'December',2011,'Picking ',1;
You can generate a list of months using a much simpler CTE, and build a dynamic SQL statement based off of that:
DECLARE #sql NVARCHAR(MAX) = N'';
;WITH n AS
(
SELECT TOP (12) d = DATEADD
(
MONTH,
-(ROW_NUMBER() OVER (ORDER BY [object_id]) - 1),
GETDATE()
)
FROM sys.objects
ORDER BY d DESC
)
SELECT #sql = #sql + N',' + CHAR(13) + CHAR(10) + DATENAME(MONTH, d)
+ ' = SUM(CASE WHEN [Year] = ' + CONVERT(VARCHAR(4), DATEPART(YEAR, d))
+ ' AND MonthAsInt = ' + CONVERT(VARCHAR(2), DATEPART(MONTH, d))
+ ' THEN Quantity ELSE 0 END)'
FROM n
ORDER BY d;
SELECT #sql = N'SELECT InvType' + #sql + '
FROM dbo.foo
GROUP BY InvType';
PRINT #sql;
-- EXEC sp_executesql #sql;
I put the PRINT there so you could test it out before running it. I wasn't sure if you needed 12 months or 13 months, you can just change the TOP (12) to TOP (13) if you want 13 months, or remove the -1 if you don't want the current month included.
If you need a dynamic pivot: see here
otherwise
This is how you do it will pivot. Of course, PIVOT requires you to know what your data will look like beforehand. If you need a dynamic pivot, then there are plenty of dynamic crosstab/pivot queries/sps that people have already written.
DECLARE #BeginDate DATETIME
DECLARE #EndDate DATETIME
SET #BeginDate = GETDATE();
SET #EndDate = DATEADD(MONTH, -12, GETDATE());
WITH CTE_DatesTable
AS
(
SELECT #EndDate AS [Date]
UNION ALL
SELECT DATEADD(dd, 1, [date])
FROM CTE_DatesTable
WHERE DATEADD(dd, 1, [date]) <= #BeginDate
)
SELECT DISTINCT DATENAME(MONTH, [date]) + ' ' + CAST(YEAR([date]) AS VARCHAR(4)) AS MonthYear,
YEAR([date]) AS YearAsInt,
MONTH([Date]) AS MonthAsInt,
case when month([date]) < 5 then 'Shipment' else 'Picking' end InvType,
floor(10 * RAND() * month([date])) Quantity
into #orig
FROM CTE_DatesTable
ORDER BY YEAR([date]), MONTH([Date])
OPTION (MAXRECURSION 0)
update #orig
set Quantity = null
where MonthYear = 'February 2011'
select * from #orig
select *
from
(
select isnull(Quantity, 0) Quantity, MonthYear from #orig
) SourceTbl
PIVOT
(
sum(Quantity)
for MonthYear in ([February 2011], [March 2011])
) PivotTbl
drop table #orig
Result:
February 2011 March 2011
0 29

Dynamic dates in SQL Server SQL statement

Thanks in advance for any help on this one.
Say I have a query that compares data across years, starting at some arbitrary year and never ending (going into the future), for the same period each year up to the last completed month (which has the characteristic that Jan data never shows until Feb 1). Say also, that one cannot use T-SQL. Is there a way to reformulate the following query to generate the dates dynamically starting from 2008/01/01 (or even just doing it for all years) and going forever without any hardcoding?
select
case
when oact.fathernum like '112%' then sum(jdt1.debit) - sum(jdt1.credit)
end as [Accounts Receivable],
jdt1.refdate as [Posting Date]
from jdt1
inner join oact on jdt1.account = oact.AcctCode
where (oact.fathernum like '1%')
and
(jdt1.refdate between '2008/01/01' and dateadd(day, -1, '2008/' + cast(month(getdate()) as varchar(2)) + '/01')
or jdt1.refdate between '2009/01/01' and dateadd(day, -1, '2009/' + cast(month(getdate()) as varchar(2)) + '/01')
or jdt1.refdate between '2010/01/01' and dateadd(day, -1, '2010/' + cast(month(getdate()) as varchar(2)) + '/01')
or jdt1.refdate between '2011/01/01' and dateadd(day, -1, '2011/' + cast(month(getdate()) as varchar(2)) + '/01')
or jdt1.refdate between '2012/01/01' and dateadd(day, -1, '2012/' + cast(month(getdate()) as varchar(2)) + '/01')
or jdt1.refdate between '2013/01/01' and dateadd(day, -1, '2013/' + cast(month(getdate()) as varchar(2)) + '/01')
or jdt1.refdate between '2014/01/01' and dateadd(day, -1, '2014/' + cast(month(getdate()) as varchar(2)) + '/01')
or jdt1.refdate between '2015/01/01' and dateadd(day, -1, '2015/' + cast(month(getdate()) as varchar(2)) + '/01')
or jdt1.refdate between '2016/01/01' and dateadd(day, -1, '2016/' + cast(month(getdate()) as varchar(2)) + '/01')
or jdt1.refdate between '2017/01/01' and dateadd(day, -1, '2017/' + cast(month(getdate()) as varchar(2)) + '/01'))
group by oact.fathernum, jdt1.refdate
Failing that, any one care to try their hand at a reformulation using T-SQL in a stored procedure that solves the problem? The date upper bound could always be the current year as long as it is dynamic.
The TSQL below shows a method of building a dynamic calendar table.
The query as shown changes the pivot date with each year, but further on is shown how you can fix the calendar 'start' date at a particular year.
select
case
when oact.fathernum like '112%' then sum(jdt1.debit) - sum(jdt1.credit)
end as [Accounts Receivable],
jdt1.refdate as [Posting Date]
from jdt1
inner join oact on jdt1.account = oact.AcctCode
inner join (select
FirstDayOfYear =DATEADD(m,datediff(m,0,getdate())-MONTH(getdate())+1,0),
FirstDayOfMonth =DATEADD(m,datediff(m,0,getdate()),0)) D
inner join master..spt_values v on v.type='P'
and v.number between 0 and 500 -- is 500 years enough? max=2047 from this table
on jdt1.refdate >= DATEADD(year,v.number,D.FirstDayOfYear)
and jdt1.refdate < DATEADD(year,v.number,D.FirstDayOfMonth)
where (oact.fathernum like '1%')
group by oact.fathernum, jdt1.refdate
The select creates a single record of 2 pivot dates, as named
inner join (select
FirstDayOfYear =DATEADD(m,datediff(m,0,getdate())-MONTH(getdate())+1,0),
FirstDayOfMonth =DATEADD(m,datediff(m,0,getdate()),0)) D
The 2 pivot dates are the first day of the **current year**, and the first day of the current month (also in the current year). If you need the first day of a **specific** year and the first day of month (current month) but in the same specific year, you can use the variation below (example for 2008-Jan-01)
select
FirstDayOfYear =cast('20080101' as datetime),
FirstDayOfMonth =dateadd(m,month(getdate())-1,'20080101')
This uses the pivot dates and the built-in number sequence to progressively add 1 year each time to the pivot dates, starting at adding 0 (for current year).
inner join master..spt_values v on v.type='P'
and v.number between 0 and 500
on jdt1.refdate >= DATEADD(year,v.number,D.FirstDayOfYear)
and jdt1.refdate < DATEADD(year,v.number,D.FirstDayOfMonth)
Notice also that instead of
date between A and B
I normally prefer
date >= A and date < B+1
Which works whether or not B includes time information. It doesn't matter for your query, but is good practice for consistence.
Start with a numbers table to generate datesets and join on it
This SO question does it for day sequences
Would somethign like this work?:
YEAR(jdt1.refdate) between 2008 and 2017
and
MONTH(jdt1.refdate) < MONTH(getdate())
If you are using SQL Server 2005+, you can simply build your calendar on the fly:
With MaxDate As
(
Select Max(refdate) As [Date]
From jdt1
)
, Calendar As
(
Select Cast( Cast(Year(GetDate())As char(4)) + '0101' As datetime ) As [StartDay]
, DateAdd(d, -1, Cast( Cast(Year(GetDate()) + 1 As char(4)) + '0101' As datetime ) )As [EndDay]
Union All
Select DateAdd(yyyy, 1, [StartDay])
, DateAdd(yyyy, 1, [EndDay])
From Calendar
Join MaxDate
On Year(DateAdd(yyyy, 1, [EndDay])) <= Year(MaxDate.[Date])
)
Select ...
From Calendar As C
Join jdt1
On jdt1.refdate Between C.StartDay And C.EndDay
Join oact
On oact.AcctCode = jdt1.account
Where oct.fathernum Like '%1'
Group By oact.fathernum, jdt1.refdate
Option ( MaxRecursion 0 );
In this solution, I started with today's Year and expanded out to the Year of the last refdate.