SSIS Variable in Data Flow Task used incorrectly - sql

In the SSIS Package I have several Data flow Tasks where I want to use one input global variable named KOERSEL to go back in time and call data set specifically in time.
When I try to run it I am getting the error:
Syntax error, permission violation, or other nonspecific error.
when I change ? to 1 in the SQL command text, the code is running fine. So what am I missing?
DECLARE #dt DATETIMEOFFSET = SWITCHOFFSET(CONVERT(DATETIMEOFFSET, GETDATE()), '-04:00')
DECLARE #interval INT = ?
SET #interval = -1 * #interval
DECLARE #DATE_OPG DATE
SELECT #DATE_OPG = A.DWH_PR_DATO
FROM TABLE AS A
WHERE YEAR(A.DWH_PR_DATO)=YEAR(DATEADD(MONTH,#interval,#dt)) AND
MONTH(A.DWH_PR_DATO)=MONTH(DATEADD(MONTH,#interval,#dt))
ORDER BY A.DWH_PR_DATO DESC
SELECT DISTINCT COLUMN 1,
COLUMN 1,
COLUMN 1,
FROM TABLE 1
WHERE DATE_OPG=#DATE_OPG
UNION ALL
SELECT DISTINCT COLUMN 2,
COLUMN 2,
COLUMN 2,
FROM TABLE 2
WHERE DATE_OPG=#DATE_OPG
...
Screenshot

I don't think that the following error is the real issue.
Incorrect syntax near ')'.
The query parser was not able to parse the query because you have added a minus sign before the question mark ?. In this answer i will try to clarify the main cause of the error you are seeing.
Parameter data type vs Variable data type
Based on the official OLEDB Source - Documentation:
The parameters are mapped to variables that provide the parameter values at run time. The variables are typically user-defined variables, although you can also use the system variables that Integration Services provides. If you use user-defined variables, make sure that you set the data type to a type that is compatible with the data type of the column that the mapped parameter references.
This implies that the parameter datatype is not related to the variable data type.
So when you are using -? inside the SQL Command the query parser are not able to identify the parameter metadata even if it is mapped to an integer variable.
You can check my answer on the link below, it contains much details with experiments:
Date calculation with parameter in SSIS is not giving the correct result
Solving the problem
(1) Force parameter data type
Try using CAST() function to force the parameter data type and assign it to a variable in the same way you have declared #dt:
DECLARE #interval INT = CAST(? as INT)
--If you want to get a negative number else ignore the row below
SET #interval = -1 * #interval
DECLARE #dt DATETIMEOFFSET = SWITCHOFFSET(CONVERT(DATETIMEOFFSET,GETDATE()),'-04:00');
DECLARE #DATE_OPG DATE;
SELECT #DATE_OPG = DWH_PR_DATEO
FROM TableName
WHERE YEAR(DWH_PR_DATO) = YEAR(DATEADD(MONTH,#interval ,#dt)) AND
MONTH(DWH_PR_DATO) = MONTH(DATEADD(MONTH,#interval ,#dt))
ORDER BY DWH_PR_DATO DESC
(2) Using Expressions
You can use Expressions while building the SQL Command:
Add a variable of type string (Example: #[User::strQuery])
Define an Expression within this variable:
"DECLARE #dt DATETIMEOFFSET = SWITCHOFFSET(CONVERT(DATETIMEOFFSET,GETDATE()),'-04:00');
DECLARE #DATE_OPG DATE;
SELECT #DATE_OPG = DWH_PR_DATEO
FROM TableName
WHERE YEAR(DWH_PR_DATO) = YEAR(DATEADD(MONTH,-" + #[User::KOERSEL] + ",#dt)) AND
MONTH(DWH_PR_DATO) = MONTH(DATEADD(MONTH,-" + #[User::KOERSEL] + ",#dt))
ORDER BY DWH_PR_DATO DESC"
In the OLEDB Source choose SQL Command from variable and Select #[User::strQuery]
Experiments
I tried a similar query using the AdventureWorks database:
DECLARE #dt DATETIMEOFFSET = SWITCHOFFSET(CONVERT(DATETIMEOFFSET, GETDATE()), '-04:00')
DECLARE #interval INT = CAST(? as INT)
SET #interval = -1 * #interval
DECLARE #DATE_OPG DATE
SELECT #DATE_OPG = A.[ModifiedDate]
FROM [AdventureWorks2016CTP3].[HumanResources].[Employee] AS A
WHERE YEAR(A.[ModifiedDate])=YEAR(DATEADD(MONTH,#interval,#dt)) AND
MONTH(A.[ModifiedDate])=MONTH(DATEADD(MONTH,#interval,#dt))
ORDER BY A.[ModifiedDate] DESC
SELECT * FROM [AdventureWorks2016CTP3].[HumanResources].[Employee]
WHERE [ModifiedDate] = #DATE_OPG
And the query is parsed successfully

Instead of -? use the following logic:
-1 * (CAST(? as int))
if you just want to pass the variable as parameter without a negative sign then just use:
(CAST(? as int))
You cannot assign a negative sign to the parameter because it will cause some conflict since the query parser will not be able to define the parameter data type.
If it still throwing and exception, check the following link it contains a workaround:
Problem With Parameter Multiplied By Negative Value In Where Clause in OLE DB Source

Related

Passing variable precision to TIMEFROMPARTS function

I'm trying to build a function that takes a string as input representing a time variable with no separators. The fraction part could have variable precision.
This is the code I came up with :
CREATE FUNCTION [dbo].[Convert_FullStringToTime]
(
-- Add the parameters for the function here
#inputString VARCHAR(17),
#fractionsPrecision INT = 0
)
RETURNS TIME(7)
AS
BEGIN
-- Declare the return variable here
DECLARE #Result TIME(7)
-- Add the T-SQL statements to compute the return value here
SELECT #Result =
TIMEFROMPARTS(
LEFT(#inputString, 2), --hh
SUBSTRING(#inputString, 3, 2), --mm
SUBSTRING(#inputString, 5, 2), --ss
RIGHT(#inputString, #fractionsPrecision), --ff
#fractionsPrecision
)
-- Return the result of the function
RETURN #Result
END
But I'm getting an error:
Scale argument is not valid. Valid expressions for data type time scale argument are integer constants and integer constant expressions.
Do I have to understand I really have to write a constant for the precision parameter ???
Why on earth has this been done that way ?
Is there a better solution than using a case statement to overcome this ridiculous problem ?
The error is actually telling you that what you want to do is explicitly not allowed. The precision parameter for TIMEFORPARTS must be a literal; it cannot be an expression, a column value or a variable. For your FUNCTION there is, in truth, little/no point in having a "variable" precision value either; a FUNCTION must also have an explicit data type defined and that include the length/scale/precision. You initially had your FUNCTION defined as a time, which is a synonym for time(7), and you have now change the FUNCTION to demonstrate that. As such it wouldn't matter what value the precision was passed, your FUNCTION would always return a time(7).
To address your latter comments:
Why on earth has this been done that way ?
Is there a better solution than using a case statement to overcome this ridiculous problem ?
I'm going to address your second comment first; it isn't a "ridiculous problem", the real problem is you want a value that doesn't have a strict definition. T-SQL is a declarative and compiled langauge; you need to explicity define what data types a value is. The fact you want a variable precision value is a strong indication of an XY Problem, however, what that problem is I don't know. There likely is a "better solution" to what you actually want to do, but without knowing what that is, we can't access that question here.
As for why it's done that way, I come back to the point of that the language is declarative and compiled; as such if you could pass a variable/expression then SQL Sevrer would know what data type to compile a column as. Take the following very simple statement:
SELECT TIMEFROMPARTS(0,0,0,0,V.I) AS T
FROM (VALUES(5),(6),(7))V(I)
Here the column V.I being (trying to be) used to define the precision for TIMEFROMPARTS. The problem though is that V.I has 3 different values, 5, 6, and 7, so what is the data type for the column defined as T? Should it be 7? 5? SQL Server doesn't know, because at the time it compiles the statement it cannot make an informed decision; for a table (rather than a VALUES table construct) the compiler wouldn't read the table first to then make a decision, that would be awful for performance.
As such you must use a literal to tell SQL Server what precision you need. Just like when you define a variable, you can't use the syntax varchar(#Len) or when you CONVERT a column you can't use the syntax CONVERT(decimal(T.P,T.S),MyColumn).
This the combination of function I came up with, taking into account the precision inherent to the TIME datatype. (Thanks to #Larnu)
First, the padding function (which SQL SERVER also lacks...)
CREATE FUNCTION [dbo].[Rpad]
(
-- Add the parameters for the function here
#inputString VARCHAR(MAX),
#paddingCharacter VARCHAR(1),
#paddingLength INT
)
RETURNS VARCHAR(MAX)
AS
BEGIN
-- Declare the return variable here
DECLARE #Result VARCHAR(MAX)
-- Add the T-SQL statements to compute the return value here
SELECT #Result =
LEFT(#inputString + REPLICATE(#paddingCharacter, #paddingLength), #paddingLength)
-- Return the result of the function
RETURN #Result
END
GO
Then the Time conversion function, which will always return a 7 precision TIME data type.
CREATE FUNCTION [dbo].[Convert_FullStringToTime]
(
-- Add the parameters for the function here
#inputString VARCHAR(13)
)
RETURNS TIME(7)
AS
BEGIN
-- Declare the return variable here
DECLARE #Result TIME(7)
-- Add the T-SQL statements to compute the return value here
SELECT #Result =
TIMEFROMPARTS(
LEFT(#inputString, 2), --hh
SUBSTRING(#inputString, 3, 2), --mm
SUBSTRING(#inputString, 5, 2), --ss
RIGHT([dbo].RPAD(#inputString, '0', 7), 7), --ff
7
)
-- Return the result of the function
RETURN #Result
END

SQL return date from function gets an error in setting variable

I get the error "Operand data type varchar is invalid for subtract operator." in line 6 where i set the dummy variable.
When i remove the first part there is no error, so i think the setting of the variable also tries to execute some of the functions in the string.
Is is possible to set a variable with functions without having the setting also trying to execute the functions? Or should this be done in an entirely different way?
All i want is the option to use dbo.TimeInterval(7) (or something like this) instead of "REPLACE([US-Date],'-','') between CONVERT(int,CONVERT(varchar(10),GETDATE()-7,112)) and CONVERT(int,CONVERT(varchar(10),GETDATE(),112))" when i want the time interval of 7 days from today...
CREATE FUNCTION dbo.TimeInterval(#Input VARCHAR(1000))
RETURNS VARCHAR(1000)
AS BEGIN
DECLARE #dummy VARCHAR(1000)
SET #dummy = 'REPLACE([US-Date],'-','') between CONVERT(int,CONVERT(varchar(10),GETDATE()-Tidsinterval,112)) and CONVERT(int,CONVERT(varchar(10),GETDATE(),112))'
SET #dummy = REPLACE(#dummy, 'Tidsinterval',#Input)
RETURN #dummy
END

Convert scientific notation back to numbers in SQL Server

I had data in Excel like
7540006
7540447
But when I import the data into SQL Server, it is saved as
7.54001e+006
7.54045e+006
So now when I try to convert it to back to original state, it's not ending up with the correct value.
I have tried following queries for conversion
declare #a varchar(40)
set #a = '7.54001e+006'
declare #b decimal(27, 12)
SELECT #b = CONVERT(REAL, #a, 2)
SELECT LTRIM(RTRIM(str(#a))), LTRIM(STR(#a))
SELECT CAST('7.54001e+006' as REAL)
and the output I am getting is addition of 3 to original value for all methods
i.e.
7540010
7540050
How do I convert it back to original state ??
Try the following query which gives the exact value
select CAST(CAST('7.54001e+006' AS FLOAT) AS bigint)
All data is stored as Unicode string 255 (DT_WSTR) in excel.
Read excel data as Unicode form. then do conversion in ssis or database using.
SELECT CAST('7.54001e+006' as REAL)
In excel data source >> connection manager >>Data access mode
== QUERY
SELECT * FROM [SheetName$]
when you will save in database that time convert value into toString() like
Convert.toString(7540006)
then it will save original value in database.

Converting Varchar to Datetime for Stored procedure input

I want to use a datetime parameter in a stored procedure, in T-SQL, that if NULL will revert to 12/31/9999.
My code looks like this:
EXEC abc.someStoredProc #i_param1, #i_param2, ISNULL(#l_Termination_date, '12/31/9999')
I get an error:
Incorrect syntax near '#l_Termination_date'
I've tried using convert and cast (for example:
ISNULL(#l_Termination_date,CAST('12/31/9999' AS datetime))
but can't seem to get it right. What am I doing wrong?
You can pass variables or literals as arguments to execute a stored procedure, (or call one of a few specific functions), but what you can't do is have arbitrary expressions.
Move it to a separate step:
SET #l_Termination_date = ISNULL(#l_Termination_date,'99991231')
EXEC abc.someStoredProc
#i_param1
, #i_param2
,#l_Termination_date
(Or use a separate variable if you don't want to overwrite #l_Termination_date)
DECLARE #l_Termination_date DATE ;
SET #l_Termination_date = ISNULL(#l_Termination_date,'12/31/9999')
EXEC dbo.USP_abc.someStoredProc (
#i_param1
, #i_param2
,#l_Termination_date )

Why would YEAR fail with a conversion error from a Date?

I got a view named 'FechasFirmaHorometros' defined as
SELECT IdFormulario,
CONVERT(Date, RValues) AS FechaFirma
FROM dbo.Respuestas
WHERE ( IdPreguntas IN (SELECT IdPregunta
FROM dbo.Preguntas
WHERE
( FormIdentifier = dbo.IdFormularioHorometros() )
AND ( Label = 'SLFYHDLR' )) )
And i have a Function named [RespuestaPreguntaHorometrosFecha] defined as
SELECT Respuestas.RValues
FROM Respuestas
JOIN Preguntas
ON Preguntas.Label = #LabelPregunta
JOIN FechasFirmaHorometros
ON FechasFirmaHorometros.IdFormulario = Respuestas.IdFormulario
WHERE Respuestas.IdPreguntas = Preguntas.IdPregunta
AND YEAR(FechasFirmaHorometros.FechaFirma) = #Anio
AND MONTH(FechasFirmaHorometros.FechaFirma) = #Mes
#LabelPregunta VARCHAR(MAX)
#Anio INT
#Mes INT
I keep getting this message upon hitting the aforementioned function while debugging another stored procedure that uses it
Conversion failed when converting date and/or time from character string.
Yet i can freely do things like
SELECT DAY(FechaFirma) FROM FechasFirmaHorometros
Why is this happening and how can i solve or work around it?
I assume that RValues is a string column of some type, for some reason. You should fix that and store date data using a date data type (obviously in a separate column than this mixed bag).
If you can't fix that, then you can prevent what Damien described above by:
CASE WHEN ISDATE(RValues) = 1 THEN CONVERT(Date, RValues) END AS FechaFirma
(Which will make the "date" NULL if SQL Server can't figure out how to convert it to a date.)
You can't prevent this simply by adding a WHERE clause, because SQL Server will often try to attempt the conversion in the SELECT list before performing the filter (all depends on the plan). You also can't force the order of operations by using a subquery, CTE, join order hints, etc. There is an open Connect item about this issue - they are "aware of it" and "hope to address it in a future version."
Short of a CASE expression, which forces SQL Server to evaluate the ISDATE() result before attempting to convert (as long as no aggregates are present in any of the branches), you could:
dump the filtered results into a #temp table, and then subsequently select from that #temp table, and only apply the convert then.
just return the string, and treat it as a date on the client, and pull YEAR/MONTH etc. parts out of it there
just use string manipulation to pull YEAR = LEFT(col,4) etc.
use TRY_CONVERT() since I just noticed you're on SQL Server 2012:
TRY_CONVERT(DATE, RValues) AS FechaFirma