Stored Procedure with variable condition and error message - sql

In my procedure, the variable #year should take two forms: 1: If #Year=1, Select all years. 2: #Year= the entered year.
Here's a sample of my code:
CREATE PROC spProcName (#Year)
AS
BEGIN
SELECT Year AS [YEAR], Item AS [ITEM]
FROM Sales
WHERE Year = #YEAR
I can make it work for #Year = 2013, but I don't know how to incorporate the #Year =1 to select all years. I'm guessing it would be with CASE.
I also have many other similar conditions with other variables, so I can't just create an IF statement.

Where Year = Case when #Year = 1 Then Year else #Year end

Alternative to John's answer, but quasi-equivalent:
WHERE (#year=1 OR year=#year)
In this case it is best to add OPTION(RECOMPILE) at the end of the query, otherwise the query won't be able to choose an index if it exists on the year column.

--If you give value 1 it will select all the records from table year wise else if you give year like 2016 it fetches all the record based on given year
ALTER PROC spProcName (#Year int)
AS
BEGIN
IF #Year = 1
BEGIN
SELECT
[Year] AS [YEAR],
Item AS [ITEM]
FROM Sales
ORDER BY [Year]
END
ELSE
SELECT
[Year] AS [YEAR],
Item AS [ITEM]
FROM Sales
WHERE DATEPART(YEAR, CAST([Year] AS date)) = #year
END

Related

SQL Server: Summary of amount for year and week number

I am trying to create a query that yields Year, Iso week and sum of amount for that year and week.
My problem is that the way I am doing it returns the amount for the first days of 2021 as being from week 53 when it actually should of course be a part of week 53 of the year 2020.
Here is my query:
SELECT
datepart(year, [MyDate]) AS [Year],
datepart(iso_week,[MyDate]) AS WeekNumber,
sum([Amount]) AS TotalAmount
FROM [Temp].[dbo].[MyTable]
GROUP BY datepart(year, [MyDate]), datepart(iso_week,[MyDate])
ORDER BY datepart(year, [MyDate]), datepart(iso_week,[MyDate])
How can this be fixed?
Sadly, SQL Server offers iso_week as an argument to datepart(), but not iso_year. Some perusing on the web suggests this code:
SELECT v.iso_year, v.iso_week,
sum([Amount]) AS TotalAmount
FROM [Temp].[dbo].[MyTable] t CROSS APPLY
(VALUES (YEAR(DATEADD(day, 26 - DATEPART(isoww, DATEFROMPARTS(YEAR(t.mydate), 1, 1)), DATEFROMPARTS(YEAR(t.mydate), 1, 1))),
datepart(iso_week, t.[MyDate])
)
) v(iso_year, iso_week)
GROUP BY iso_year, iso_week
ORDER BY iso_year, iso_week
I found a solution by doing this:
SELECT
dbo.GetIsoYear(MyDate) AS [Year],
datepart(iso_week,MyDate) AS WeekNumber,
sum(Amount) AS 'TotalAmount'
FROM MyTable
GROUP BY dbo.GetIsoYear(MyDate), datepart(iso_week,MyDate)
ORDER BY dbo.GetIsoYear(MyDate), datepart(iso_week,MyDate)
and here is the function I am using:
ALTER FUNCTION [dbo].[GetIsoYear](#Date datetime)
RETURNS int
AS
BEGIN
DECLARE #ResultVar int
DECLARE #IsoWeek int
DECLARE #Month int
SELECT #IsoWeek = DATEPART(ISO_WEEK,#Date)
SELECT #Month = DATEPART(MONTH,#Date)
IF #IsoWeek = 53 AND #Month = 1
SET #ResultVar = YEAR(#Date) - 1
ELSE
SET #ResultVar = YEAR(#Date)
RETURN #ResultVar
END
I do not know if using a function here has performance issues but I would think that it should run rather fast.

If/Then/Else in Formatting a Date

I am trying to get the fiscal period and year out of an invoice date. Using the month() function together with the Case I am able to get the period. since Period 1 is in November I need to do a +1 1 the year when this is true
Using the IF function together with the date functions are now working for me.
My query is
Select a.OrderAccount
,a.InvoiceAccount
,a.InvoiceDate
,year(a.InvoiceDate) as Year
,month(a.InvoiceDate) as Month,
Case month(a.InvoiceDate)
WHEN '11' THEN '1' -- increase year by +1
WHEN '12' THEN '2'-- increase year by +1
WHEN '1' THEN '3'
WHEN '2' THEN '4'
WHEN '3' THEN '5'
Any advice would be appreciated. Thanks
Use DATEADD to just add 2 months to the original date:
MONTH(DATEADD(month,2,a.InvoiceDate)) as FiscalMonth,
YEAR(DATEADD(month,2,a.InvoiceDate)) AS FiscalYear,
Create and populate a Calendar Table (it makes working with dates much easier).
create table Calendar
(
id int primary key identity,
[date] datetime,
[day] as datepart(day, [date]) persisted,
[month] as datepart(month, [date]) persisted,
[year] as datepart(year, [date]) persisted,
day_of_year as datepart(dayofyear, [date]) persisted,
[week] as datepart(week, [date]),
day_name as datename(dw, [date]),
is_weekend as case when datepart(dw, [date]) = 7 or datepart(dw, [date]) = 1 then 1 else 0 end,
[quarter] as datepart(quarter, [date]) persisted
--etc...
)
--populate the calendar
declare #date datetime
set #date = '1-1-2000'
while #date <= '12-31-2100'
begin
insert Calendar select #date
set #date = dateadd(day, 1, #date)
end
Then, create a FiscalYear view:
create view FiscalYear
as
select
id,
case when month = 11 or month = 12 then year + 1 else year end as [year]
from Calendar
So, whenever you need the fiscal year of a given date, just use something like the following query:
select C.*, FY.year fiscal_year from Calendar C inner join FiscalYear FY on FY.id = C.id
Of course, since fiscal year is just a computation on a column, you could also just make it a part of the calendar table itself. Then, it's simply:
select * from Calendar
If you want to stick with arithmetic: The fiscal month is ( Month( a.InvoiceDate ) + 1 ) % 12 + 1 and the value to add to the calendar year to get the fiscal year is Month( a.InvoiceDate ) / 11.
The following code demonstrates 12 months:
with Months as (
select 1 as M
union all
select M + 1
from Months
where M < 12 )
select M, ( M + 1 ) % 12 + 1 as FM, M / 11 as FYOffset
from Months;
D Stanley's answer makes your intention clearer, always a consideration for maintainability.
If you have this logic in 10 different places and the logic changes starting (say) on 1/1/2018 you will have a mess on your hands.
Create a function that has the logic and then use the function like:
SELECT InvoiceDate, dbo.FiscalPeriod(InvoiceDate) AS FP
FROM ...
Something like:
CREATE FUNCTION dbo.FiscalPeriod(#InvoiceDate DateTime)
RETURNS int
AS BEGIN
DECLARE #FiscalDate DateTime
SET #FiscalDate = DATEADD(month, 2, #InvoiceDate)
RETURN YEAR(#FiscalDate) * 100 + MONTH(#FiscalDate)
END
This returns values like 201705, but you could have dbo.FiscalPeriodMonth() and dbo.FiscalPeriodYear() if you needed. And you can have as complicated logic as you need in one place.

How to change a calender tables last week value from 1 to a continuous value

Initial Point:
I create a calender table with a function (see below). I use this table e.g. to sum entries for each week in the current year.
Problem:
The calculations are wrong for the first week, since the last week in the year has the value 1 as well as the first week in the year.
Question:
Since the calender table is used for many different queries it is not possible to solve this with just a 'Where' Clause modification. Is it possible to create a calender table where the weeks are just continuous including the last week?
FUNCTION [dbo].[fct_Days_Periode](#startDate datetime, #endDate datetime) RETURNS #RET TABLE
( DateA datetime,
Year as YEAR(DateA),
QuarterNr as DATEPART(quarter, DateA),
Quarter as 'Quarter '+CAST(DATEPART(quarter, DataA) as varchar(10)),
MonthNr as MONTH(DataA),
MonthA as DATENAME(month, DateA),
KW as DATEPART(ISO_WEEK, DataA),
WeekdayA as DATENAME(weekday, DataA)
)
AS
BEGIN
WHILE #startDate<=#endDate
BEGIN
INSERT INTO #RET (DataA) VALUES (#startDate)
SET #startDate=DATEADD(day, 1, #startDate)
END
RETURN
END

How to write select query for this?

I have column COMPONENT_AMOUNT(money) ,MONTH_FOR(int), YEAR_FOR(int) and COMPONENT_TYPE(int). I want to find the sum of amount according to condition. I have written my query like this but it solve my purpose.
My purpose is that if one select Nov-2010 then it will sum the amount up to this selected month including all the month of 2009.
My query is given below ,please modify it:
SELECT SUM(Convert(Numeric(7,2), Round([COMPONENT_AMOUNT],2,1)))
FROM [TEAM_FUNDS_DETAILS]
WHERE YEAR_FOR <= 1 AND MONTH_FOR <= 1 AND [COMPONENT_TYPE] = 1
If You need only one result per query I think that this is code
declare #year int
declare #month int
set #year = 2010 --desire year
set #month = 8 --desire month
select sum(COMPONENT_AMOUNT)
from [TEAM_FUNDS_DETAILS]
WHERE
[COMPONENT_TYPE] = 1
and (
YEAR_FOR < #year
or (year_for=#year and month_for<=#month)
)

Convert Month Number to Month Name Function in SQL

I have months stored in SQL Server as 1,2,3,4,...12. I would like to display them as January,February etc. Is there a function in SQL Server like MonthName(1) = January? I am trying to avoid a CASE statement, if possible.
I think this is the best way to get the month name when you have the month number
Select DateName( month , DateAdd( month , #MonthNumber , 0 ) - 1 )
Or
Select DateName( month , DateAdd( month , #MonthNumber , -1 ) )
A little hacky but should work:
SELECT DATENAME(month, DATEADD(month, #mydate-1, CAST('2008-01-01' AS datetime)))
SELECT DATENAME(month, GETDATE()) AS 'Month Name'
SUBSTRING('JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC ', (#intMonth * 4) - 3, 3)
Use the Best way
Select DateName( month , DateAdd( month , #MonthNumber , -1 ))
It is very simple.
select DATENAME(month, getdate())
output : January
Starting with SQL Server 2012, you can use FORMAT and DATEFROMPARTS to solve this problem. (If you want month names from other cultures, change: en-US)
select FORMAT(DATEFROMPARTS(1900, #month_num, 1), 'MMMM', 'en-US')
If you want a three-letter month:
select FORMAT(DATEFROMPARTS(1900, #month_num, 1), 'MMM', 'en-US')
If you really want to, you can create a function for this:
CREATE FUNCTION fn_month_num_to_name
(
#month_num tinyint
)
RETURNS varchar(20)
AS
BEGIN
RETURN FORMAT(DATEFROMPARTS(1900, #month_num, 1), 'MMMM', 'en-US')
END
You can use the inbuilt CONVERT function
select CONVERT(varchar(3), Date, 100) as Month from MyTable.
This will display first 3 characters of month (JAN,FEB etc..)
in addition to original
SELECT DATENAME(m, str(2) + '/1/2011')
you can do this
SELECT DATENAME(m, str([column_name]) + '/1/2011')
this way you get names for all rows in a table. where [column_name] represents a integer column containing numeric value 1 through 12
2 represents any integer, by contact string i created a date where i can extract the month. '/1/2011' can be any date
if you want to do this with variable
DECLARE #integer int;
SET #integer = 6;
SELECT DATENAME(m, str(#integer) + '/1/2011')
In some locales like Hebrew, there are leap months dependant upon the year so to avoid errors in such locales you might consider the following solution:
SELECT DATENAME(month, STR(YEAR(GETDATE()), 4) + REPLACE(STR(#month, 2), ' ', '0') + '01')
The following works for me:
CAST(GETDATE() AS CHAR(3))
Use this statement to convert Month numeric value to Month name.
SELECT CONVERT(CHAR(3), DATENAME(MONTH, GETDATE()))
Just subtract the current month from today's date, then add back your month number. Then use the datename function to give the full name all in 1 line.
print datename(month,dateadd(month,-month(getdate()) + 9,getdate()))
Sure this will work
select datename(M,GETDATE())
SELECT DateName(M, DateAdd(M, #MONTHNUMBER, -1))
To convert month number to month name, try the below
declare #month smallint = 1
select DateName(mm,DATEADD(mm,#month - 1,0))
You can use the convert functin as below
CONVERT(VARCHAR(3), DATENAME(MM, GETDATE()), 100)
i think this is enough to get month name when u have date.
SELECT DATENAME(month ,GETDATE())
SELECT DATENAME(MONTH,dateadd(month, -3,getdate()))
This one worked for me:
#MetricMonthNumber (some number)
SELECT
(DateName( month , DateAdd( month , #MetricMonthNumber - 1 , '1900-01-01' ) )) AS MetricMonthName
FROM TableName
From a post above from #leoinfo and #Valentino Vranken. Just did a quick select and it works.
Declare #MonthNumber int
SET #MonthNumber=DatePart(Month,GETDATE())
Select DateName( month , DateAdd( month , #MonthNumber , 0 ) - 1 )
Explaination:
First Decalre Variable MonthNumber
Get Current Month for DatePart which Return Month Number
Third Query Return Month Name
select monthname(curdate());
OR
select monthname('2013-12-12');
Working for me
SELECT MONTHNAME(<fieldname>) AS "Month Name" FROM <tablename> WHERE <condition>
you can get the date like this.
eg:- Users table
id name created_at
1 abc 2017-09-16
2 xyz 2017-06-10
you can get the monthname like this
select year(created_at), monthname(created_at) from users;
output
+-----------+-------------------------------+
| year(created_at) | monthname(created_at) |
+-----------+-------------------------------+
| 2017 | september |
| 2017 | june |
You can create a function like this to generate the Month and do
SELECT dbo.fn_GetMonthFromDate(date_column) as Month FROM table_name
/****** Object: UserDefinedFunction [dbo].[fn_GetMonthFromDate] Script Date: 11/16/2018 10:26:33 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fn_GetMonthFromDate]
(#date datetime)
RETURNS varchar(50)
AS
BEGIN
DECLARE #monthPart int
SET #monthPart = MONTH(#date)
IF #monthPart = 1
BEGIN
RETURN 'January'
END
ELSE IF #monthPart = 2
BEGIN
RETURN 'February'
END
ELSE IF #monthPart = 3
BEGIN
RETURN 'March'
END
ELSE IF #monthPart = 4
BEGIN
RETURN 'April'
END
ELSE IF #monthPart = 5
BEGIN
RETURN 'May'
END
ELSE IF #monthPart = 6
BEGIN
RETURN 'June'
END
ELSE IF #monthPart = 7
BEGIN
RETURN 'July'
END
ELSE IF #monthPart = 8
BEGIN
RETURN 'August'
END
ELSE IF #monthPart = 9
BEGIN
RETURN 'September'
END
ELSE IF #monthPart = 10
BEGIN
RETURN 'October'
END
ELSE IF #monthPart = 11
BEGIN
RETURN 'November'
END
ELSE IF #monthPart = 12
BEGIN
RETURN 'December'
END
RETURN NULL END
Here is my solution using some information from others to solve a problem.
datename(month,dateadd(month,datepart(month,Help_HelpMain.Ticket_Closed_Date),-1)) as monthname
There is no system defined function in SQL server. But you can create your own user-defined function- a scalar function. You would find scalar functions in the Object Explorer for your database: Programmability->Functions->Scalar-valued Functions. Below, I use a table variable to bring it all together.
--Create the user-defined function
CREATE FUNCTION getmonth (#num int)
RETURNS varchar(9) --since 'September' is the longest string, length 9
AS
BEGIN
DECLARE #intMonth Table (num int PRIMARY KEY IDENTITY(1,1), month varchar(9))
INSERT INTO #intMonth VALUES ('January'), ('February'), ('March'), ('April'), ('May')
, ('June'), ('July'), ('August') ,('September'), ('October')
, ('November'), ('December')
RETURN (SELECT I.month
FROM #intMonth I
WHERE I.num = #num)
END
GO
--Use the function for various months
SELECT dbo.getmonth(4) AS [Month]
SELECT dbo.getmonth(5) AS [Month]
SELECT dbo.getmonth(6) AS [Month]
to_char(to_date(V_MONTH_NUM,'MM'),'MONTH')
where V_MONTH_NUM is the month number
SELECT to_char(to_date(V_MONTH_NUM,'MM'),'MONTH') from dual;
Use this statement for getting month name:
DECLARE #date datetime
SET #date='2015/1/4 00:00:00'
SELECT CAST(DATENAME(month,#date ) AS CHAR(3))AS 'Month Name'
This will give you short month name. Like this: Jan, Feb, Mar, etc.
Try this: SELECT MONTHNAME(concat('1970-',[Month int val],'-01'))
For example- SELECT MONTHNAME(concat('1970-',4,'-01'))
The answer is - April