Is there a way to name a column name with the value of a variable in SQL? - variables

I want to give an colomnnem the value of a [text] plus a [variable]. Example, i declared a varibale with the name [MONTH] and give the variable the value [8]. Now i have a CASE statement that ends with AS and then the name of the column, lets say MONTH. Now i want the columnname to be [MONTH] with the value 8.
DECLARE #End Int
DECLARE #Begin Int
**DECLARE #Month Int**
DECLARE #Year Int
SET #Begin=1
**SET #Month=2**
SET #End=28 --(Must be automated so that in the 'month' 2 the value will be 28)
SET #Year=2021
SELECT code,num,Convert(date,starting)start,Convert(date,ending)end
,CASE WHEN Convert(date,starting)>=DATEFROMPARTS(#Year,#Month,#Begin) AND Convert(date,starting) <=DATEFROMPARTS(#Year,#Month,#End) AND ending IS NULL
THEN (SELECT COUNT(IsWorkingDay) FROM dbo.DimDate WHERE (DateValue >= CONVERT(Date,starting) AND (DateValue <= DATEFROMPARTS(#Year,#Month,#End))))
WHEN starting < DATEFROMPARTS(#Year,#Month,#End) THEN (SELECT COUNT(Days) FROM dbo.DimDate WHERE (DateValue >= DATEFROMPARTS(#Year,#Month,#Begin) AND DateValue <= DATEFROMPARTS(#Year,#Month,#End)))
END
AS **' + Month(#Month) + '**
FROM [Table]

Related

How to avoid not to query tables or views in scalar functions?

I have scalar functions( 4 functions) in my View. It drastically reduces the view's performance. I believe the reason for that is I use SELECT queries in my scalar functions.
EG:
CREATE FUNCTION [dbo].[udf_BJs_GENERAL]
(
#TankSystemId int,
#TimeStamp datetime2(7)
)
RETURNS varchar(10)
AS
BEGIN
DECLARE #leakChk varchar(10);
DECLARE #allowableVariance float;
DECLARE #GallonsPumped int;
DECLARE #DailyOverOrShort float;
DECLARE #TimePeriod datetime2(7);
DECLARE #ReportDate datetime2(7)
SELECT TOP 1 #TimePeriod = Date
FROM [bjs].udv_DailySiraData
where TankSystemId=#TankSystemId ORDER BY Date DESC
SET #ReportDate=#TimePeriod
IF( #TimeStamp <= #TimePeriod)
SET #ReportDate=#TimeStamp
SELECT #GallonsPumped = SUM(GallonsPumped)
FROM [bjs].[udv_DailySiraData]
where TankSystemId=#TankSystemId
and Date <=#ReportDate and Date >= DATEADD(mm, DATEDIFF(mm,0,#ReportDate), 0)
SELECT #DailyOverOrShort = SUM(DailyVar)
FROM [bjs].[udv_DailySiraData]
where TankSystemId=#TankSystemId
and Date <=#ReportDate and Date >= DATEADD(mm, DATEDIFF(mm,0,#ReportDate), 0)
SELECT #allowableVariance= (#GallonsPumped/100) + 130
SET #leakChk='FAIL'
IF (#allowableVariance > ABS(#DailyOverOrShort))
SET #leakChk = 'PASS'
RETURN #leakChk;
How can i avoid such situations? Is there a way to do select queries in my View and pass that result to my scalar function?
Try this:
create function dbo.udf_BJs_GENERAL(
#TankSystemId int,
#TimeStamp datetime2(7)
) returns varchar(10) as
with dates as (
select top 1
ReportDate = case when #TimeStamp <= Date then #TimeStamp else Date
from bjs.udv_DailySiraData
where TankSystemId=#TankSystemId
order by Date desc
),
gallons as (
select
allowableVariance = ( sum(GallonsPumped)/100) + 130,
DailyOverOrShort = sum(DailyVar)
from bjs.udv_DailySiraData data
join dates
on data.Date <= dates.ReportDate
and date.Date >= dateadd(mm, datediffmm, 0, dates.ReportDate), 0)
where TankSystemId = #TankSystemId
)
select
leakChk = cast( case when allowableVariance > ABS(DailyOverOrShort))
then 'PASS' else 'FAIL' end as varchar(10) )
from gallons
your case is special, your have a special input parameter,assue the timestamp parameter is on Day level
This view will return check result of each TankSystemId on every day.
Then join will your query with TankSystemId and Day.
But if the input parameter is more detail. I think it is difficult to convert this function to view
CREATE view [dbo].[uvw_BJs_GENERAL]
AS
BEGIN
/*
SET #ReportDate=#TimePeriod
IF( #TimeStamp <= #TimePeriod)
SET #ReportDate=#TimeStamp
*/
SELECT TankSystemId,b.[Date]
,GallonsPumped = SUM(GallonsPumped),DailyOverOrShort = SUM(DailyVar)
,leakChk=CASE WHEN (SUM(GallonsPumped)/100) + 130)> ABS(SUM(DailyVar)) THEN 'PASS' ELSE 'FAIL' END
FROM [bjs].[udv_DailySiraData] AS a
INNER JOIN (
SELECT CONVERT(DATE,[Date]) AS [Date] FROM [bjs].[udv_DailySiraData] GROUP BY TankSystemId, CONVERT(DATE,[Date])
) b ON a.TankSystemId=b.TankSystemId AND DATEDIFF(d,a.[Date],b.[Date])>=0
-- and Date <=#ReportDate and Date >= DATEADD(mm, DATEDIFF(mm,0,#ReportDate), 0)
GROUP BY TankSystemId,b.[Date]
END

How to add hours to work day in SQL?

I have seen many example adding working date (business days) to date in SQL. But I would like to add hour.
For example; I would like to add 36 hour to date not in Sunday , Saturday
Could one help me about it ?
CREATE FUNCTION AddWorkDays
(
#WorkingDays As Int,
#StartDate AS DateTime
)
RETURNS DateTime
AS
BEGIN
DECLARE #Count AS Int
DECLARE #i As Int
DECLARE #NewDate As DateTime
SET #Count = 0
SET #i = 0
WHILE (#i < #WorkingDays) --runs through the number of days to add
BEGIN
-- increments the count variable
SELECT #Count = #Count + 1
-- increments the i variable
SELECT #i = #i + 1
-- adds the count on to the StartDate and checks if this new date is a Saturday or Sunday
-- if it is a Saturday or Sunday it enters the nested while loop and increments the count variable
WHILE DATEPART(weekday,DATEADD(d, #Count, #StartDate)) IN (1,7)
BEGIN
SELECT #Count = #Count + 1
END
END
-- adds the eventual count on to the Start Date and returns the new date
SELECT #NewDate = DATEADD(d,#Count,#StartDate)
RETURN #NewDate
END
GO
The following will add N hours to a date (excluding Saturday and Sundays).
Example
Declare #Date1 datetime = '2017-04-28'
Declare #Hours int = 36
Select D=max(D)
From (
Select D,HN=-1+Row_Number() over (Order by D)
From (Select D=DateAdd(HOUR,-1+Row_Number() Over (Order By (select null)),#Date1) From master..spt_values n1 ) D
Where DateName(WEEKDAY,D) not in ('Saturday','Sunday')
) D1
Where HN=#Hours
Returns
2017-05-01 12:00:00.000
is it what you are looking for?
declare #num_hours int;
set #num_hours = 1;
select dateadd(HOUR, #num_hours, getdate()) as time_with_hour;
declare #num_hours int;
set #num_hours = 5;
select dateadd(HOUR, #num_hours, getdate()) as time_added,
getdate() as curr_date
This question is already answered Here

Defining type as a variable - DATEADD(type, value, date) - SQL [duplicate]

This question already has answers here:
SQL Dynamic DatePart when using DateDiff
(6 answers)
Closed 5 years ago.
I had to change the date in one of a column of my SQL table (datetime field), increment YEAR by 1. The simple way to perform this action would be (unless someone knows a better way) to update table and SET column with DATEADD()
-- sample 1
-- DATEADD(type, value, date)
SELECT DATEADD(YEAR, 1, GETDATE())
Since I'm a lazy programmer, I don't want to keep updating the tables every time we run in to such situation. So I decided to write a small script (function) which gets TYPE, VALUE from the user and perform the operation. But I ran into a situation where I can't use TYPE as a variable.
-- Sample 2
-- Error in the code
DECLARE #type VARCHAR(10) = 'YEAR'
,#increment INT = 1
SELECT DATEADD(#type, #increment, GETDATE())
I can write a case statement where based on the 'TYPE' value I can select the update statement.
-- Sample 3
DECLARE #type VARCHAR(10) = 'YEAR'
,#increment INT = 1
UPDATE Table_name
SET Column_date = CASE #type WHEN 'YEAR' THEN DATEADD(YEAR, #increment, Column_date)
WHEN 'MONTH' THEN DATEADD(MONTH, #increment, Column_date)
-- and so on
END
But is there a way to perform the action without the case statement, or can anyone make sample code '2' run?
P.S. Its more of a knowledge based question - Its not holding me back, I'm just curious to know if its possible.
Thanks! :)
You could just get all of the type values from the user and just update them all at once.. Just default to 0 the ones they don't want to change
DECLARE #Year INT = 0,
#Month INT = 0,
#Day INT = 0
UPDATE Table_name
SET Column_date = DATEADD(YEAR, #Year, DATEADD(Month, #Month, DATEADD(Day, #Day, Column_date)))
An alternative to already provided solution is to use a dynamic SQL:
Setup:
-- drop table dbo.DateTest
create table dbo.DateTest
(
TheDate DATE,
UpdatedDate DATE
)
TRUNCATE TABLE dbo.DateTest
GO
INSERT INTO dbo.DateTest (TheDate) VALUES ('20150203'), ('20150506'), ('20141231')
GO
Code:
select * from dbo.DateTest
DECLARE #type VARCHAR(8) = 'year' -- this must be a DATEADD recognizable token
DECLARE #increment INT = 2
DECLARE #Sql NVARCHAR(1000) = N'
UPDATE dbo.DateTest SET UpdatedDate = DATEADD(' + #type + ', #increment, TheDate)'
EXEC sp_executesql #Sql, N' #increment INT', #increment
select * from dbo.DateTest
I wish date part could be provided as parameter, but it does not seem to be possible.

The data types varchar and int are incompatible in the concat operator

I've been stuck for the past two days execute it give the error:
The data types varchar and int are incompatible in the concat operator
Here is my table:
create table salestable
(
id int identity(1,1) not null primary key,
empid char(5),
datesold date,
monthonly varchar(50),
amount money
)
This code inserts the dummy record into dbo.salestable for working in salestable, debug and step into the code that give the debug and understanding code
declare #outercounter int = 1
declare #innercounter int = 1
while #outercounter <= (select count(name) from namestable)
begin
while #innercounter <= datediff(day, getdate() -datepart(day, getdate()), {fn concat('12/31/',Datepart(year,getdate()))})
begin
insert into salestable (empid, datesold, monthonly, amount)
values (#outercounter,
getdate() - datepart(day, getdate()) + #innercounter,
Datename(month, getdate() - datepart(day, getdate()) + #innercounter),
rand() * 10000)
set #innercounter = #innercounter +1
end
set #outercounter = #outercounter + 1
set #innercounter = 1
end
select * from dbo.salestable
fn concat('12/31/',CAST(Datepart(year,getdate()) AS VARCHAR(10)))
Try this

How to optimize a cycle in stored procedure [T-SQL]

I have this stored procedure in T-SQL for splitting a DATETIME into shifts.
I would divide the DATETIME START and DATETIME END into shifts (for example, one shift for hours or one shift every 15 minutes). I should this shift into a temporary table for use it in another query.
So for this I have create this cycle:
BEGIN
SET #DATASTART = '2014-11-28 06:00:00'
SET #DATAEND = '2014-11-28 21:00:00'
--DICHIARO DUE VARIABILI DATA CHE UTILIZZO
--PER MANTENERE I DUE SHIFT
DECLARE #DataFirstShift as DATETIME
DECLARE #DataLastShift as DATETIME
--DICHIARO UN CONTATORE PER POPOLARE IL CAMPO ID
DECLARE #Contatore as INT
SET #Contatore = 0
--SETTO LA DATA FIRSTSHIFT A DATASTART
SET #DataFirstShift = #DATA_START
WHILE(#DataFirstShift <= #DATA_END)
BEGIN
--POPOLO LA DATA LAST CON UN ORA IN PIU RISPETTO ALLA PRIMA DATA
IF #Shift LIKE 'All'
BEGIN
SET #DataLastShift = DATEADD(HOUR,1,#DataFirstShift)
END
ELSE
BEGIN
SET #DataLastShift = DATEADD(MINUTE,15,#DataFirstShift)
END
INSERT INTO #TemporaryTable2 (ID,DATASTART,DATAEND)
VALUES (#Contatore,#DataFirstShift,#DataLastShift)
SET #DataFirstShift=#DataLastShift
--INCREMENTO IL CONTATORE
SET #Contatore+=1
END
END
This method works but I this cycle is slow. I want to know if exist a method faster than it.
Can someone help me? Regards
Try below :
--param of SP
DECLARE #DATASTART DATETIME = '2014-11-28 06:00:00'
DECLARE #DATAEND DATETIME = '2014-11-28 21:00:00'
DECLARE #Shift VARCHAR(50) = 'All'
--body
DECLARE #TemporaryTable2 TABLE
(
id INT,
startdate DATETIME,
enddate DATETIME
)
DECLARE #id INT = 0
IF #Shift LIKE 'All'
BEGIN
INSERT INTO #TemporaryTable2
SELECT N.number + 1 AS id,
startdate,
enddate
FROM master..spt_values N
CROSS apply (SELECT Dateadd(dd, N.number, #DATASTART),
Dateadd(dd, N.number + 1, #DATASTART)) AS D(startdate, enddate)
WHERE N.number BETWEEN 0 AND Datediff(dd, #DATASTART, #DATAEND)
AND N.type = 'P'
END
ELSE
BEGIN
INSERT INTO #TemporaryTable2
SELECT N.number + 1 AS id,
startdate,
enddate
FROM master..spt_values N
CROSS apply (SELECT Dateadd(MINUTE, N.number * 15, #DATASTART),
Dateadd(MINUTE, ( N.number + 1 ) * 15, #DATASTART)) AS D(startdate, enddate)
WHERE N.number BETWEEN 0 AND ( Datediff(MINUTE, #DATASTART, #DATAEND) / 15 )
AND N.type = 'P'
END
SELECT *
FROM #TemporaryTable2
A similar question is present here. The only limitation of this method is spt_values ranges from 0 to 2047 for type = 'p'. Hence it can return maximum 2047 rows.