Passing a Date variable in a Openrowset query - sql-server

I have this Openrowset Query where I'm able to pass a Path to get the correct Excel file. I can't figure out the exact number of quotes and/or the type conversion
I need to pass a WHERE statement to get a specific date in the table. I'm coming from VBA where you put 2 quotes and 2 & and you're all set. It seems SQL needs hundreds of them! (If someone has a link to an online university about SQL quotes that'd be much appreciated too)
set #sql1 = 'select *
FROM OPENROWSET(''Microsoft.ACE.OLEDB.12.0'',
''Excel 12.0;Database=' + #filePath1 + '' + ';' + '''' + ',
''Select * from [Sheet1$] '''+')'
exec(#sql1)
I'd like to add WHERE DATE = #PnLDate

The rule is very similar to what you know but it applies to single quote '. When you want one of them inside a string you escape it using two ''. Apart of them, you must have one for openning and one for closing.
The string you show, is a bit complicated just because it contains innecesary empty strings, and secuentialy contatenated stirngs that can be replaced just for only one resultant string. Below a simiplificated version of your string:
set #sql1 = 'select *
FROM OPENROWSET(''Microsoft.ACE.OLEDB.12.0'',
''Excel 12.0;Database=' + #filePath1 + ';'',
''Select * from [Sheet1$] '')'
With your requested where may be:
DECLARE #PnLDate datetime -- may be varchar instead, if so, must remove convert(....) and use straight #PnLDate
set #PnLDate = '2014/08/01'
set #sql1 = 'select *
FROM OPENROWSET(''Microsoft.ACE.OLEDB.12.0'',
''Excel 12.0;Database=' + #filePath1 + ';'',
''Select * from [Sheet1$] where DATE = #'+ -- hash # is MS Access delimiter for dates
convert(varchar(25), #PnLDate, 111)
+'#'')' -- results in #2014/08/01#
Be warned that when you use "dynamic SQL" your data can inject malicious code on the string. read about sql Injection

Related

Passing Int to dynamic stored procedure fails

I have a dynamic stored procedure in SQL Server that works well to pivot a table:
CREATE PROCEDURE dbo.DynamicPivotTableInSql
#ColumnToPivot NVARCHAR(255),
#ListToPivot NVARCHAR(255),
#SurveyID INT=10
AS
BEGIN
DECLARE #SqlStatement NVARCHAR(MAX)
SET #SqlStatement = N'SELECT *
FROM
(SELECT
[resp_id], [benefit], [weight]
FROM Segment_Responses) myResults
PIVOT
(SUM([weight])
FOR [' + #ColumnToPivot + ']
IN (' + #ListToPivot + ')) AS PivotTable';
EXEC (#SqlStatement)
END
and I call it like this
EXEC DynamicPivotTableInSql
#ColumnToPivot = 'benefit',
#ListToPivot = '[OBSERVABILITY], [COST], [EASE OF USE], [SERVICE]'
Here is where I run into problems. You'll notice I have hardcoded #SurveyID = 10 and if I try to add that as a where statement in the stored procedure like this:
FROM Segment_Responses
WHERE survey_id = ' + #SurveyID + '
and run the stored procedure again I get this error:
Conversion failed when converting the nvarchar value '
SELECT * FROM (
SELECT
[resp_id],
[benefit],
[weight]
FROM Segment_Responses where survey_id=' to data type int.
I've tried to solve this many ways (e.g., passed the Int variable instead of hard coding it) but always get the same result. Any ideas what is going on?
Just to try to add some clarity, when you add together two different types, SQL Server will (where it can) implicitly convert one to the other - the result must be a single type after all.
It decides which one to convert "to the other" based on an order of precedence.
So where you are trying to concatenate a varchar with an int, the int has the higher order of precedence. This is also a common cause of errors and bugs when using a case expression when mixing types in different execution paths of the expression.
You need to be explicit and cast the int to a varchar.
Ideally you would use a parameterised query which would also reuse the cached execution plan - this may be beneficial if the cardinality of the data is similar but sometimes making the value part of the query dynamically can be advantagous, it depends on the use-case.
This is why the syntax EXEC (#SQL) is strongly suggested against. Use sys.sp_executesql and parametrise your statement:
SET #SQL = N'SELECT ...
FROM ...
WHERE survey_id = #SurveyID ...;';
EXEC sys.sp_executesql #SQL, N'#SurveyID int',SurveyID;
The + only works with strings. If you use a number TSQL assumes you are trying to use the addition operator, and tries to convert the string argument to int.
eg this
select 1 + '2'
works and returns 3.
Use CONCAT instead of +, or use an explicit conversion on the int.
eg
WHERE survey_id = ' + cast(#SurveyID as varchar(20)) + '

T-SQL : using parameter as an operator

Is there a way to parameterize the arithmetic operators (<, >, =, >=, <=) in T-SQL?
Something like this:
DECLARE #Operator
SET #Operator = '>='
SELECT *
FROM Table
WHERE Date #Operator '7/1/2017'
Also, I am testing to add additional parameter using functions EXEC('SELECT SiteLongName, * FROM Reporting.Survey_Details WHERE CallDate ' + #Operator + '''7/1/2017''' + 'and SiteLongName in (select value from dbo.FnSplit(''' + #Site + ''''+'',''+'','')) , but it is erroring out.
You can if you use dynamic SQL.
Example :
DECLARE #Operator VARCHAR(2)
SET #Operator = '>='
EXEC('SELECT * FROM TABLE WHERE Date ' + #Operator + ' ''7/1/2017''')
As you can see in the example, handling quotes in dynamic SQL can be a pain. Though it's no big deal in your example.
Be aware that without proper care, dynamic SQL open a vulnerability in your system where user could use SQL Injection attacks against your program.

Generate column name dynamically in sql server

Please look at the below query..
select name as [Employee Name] from table name.
I want to generate [Employee Name] dynamically based on other column value.
Here is the sample table
s_dt dt01 dt02 dt03
2015-10-26
I want dt01 value to display as column name 26 and dt02 column value will be 26+1=27
I'm not sure if I understood you correctly. If I'am going into the wrong direction, please add comments to your question to make it more precise.
If you really want to create columns per sql you could try a variation of this script:
DECLARE #name NVARCHAR(MAX) = 'somename'
DECLARE #sql NVARCHAR(MAX) = 'ALTER TABLE aps.tbl_Fabrikkalender ADD '+#name+' nvarchar(10) NULL'
EXEC sys.sp_executesql #sql;
To retrieve the column name from another query insert the following between the above declares and fill the placeholders as needed:
SELECT #name = <some colum> FROM <some table> WHERE <some condition>
You would need to dynamically build the SQL as a string then execute it. Something like this...
DECLARE #s_dt INT
DECLARE #query NVARCHAR(MAX)
SET #s_dt = (SELECT DATEPART(dd, s_dt) FROM TableName WHERE 1 = 1)
SET #query = 'SELECT s_dt'
+ ', NULL as dt' + RIGHT('0' + CAST(#s_dt as VARCHAR), 2)
+ ', NULL as dt' + RIGHT('0' + CAST((#s_dt + 1) as VARCHAR), 2)
+ ', NULL as dt' + RIGHT('0' + CAST((#s_dt + 2) as VARCHAR), 2)
+ ', NULL as dt' + RIGHT('0' + CAST((#s_dt + 3) as VARCHAR), 2)
+ ' FROM TableName WHERE 1 = 1)
EXECUTE(#query)
You will need to replace WHERE 1 = 1 in two places above to select your data, also change TableName to the name of your table and it currently puts NULL as the dynamic column data, you probably want something else there.
To explain what it is doing:
SET #s_dt is selecting the date value from your table and returning only the day part as an INT.
SET #query is dynamically building your SELECT statement based on the day part (#s_dt).
Each line is taking #s_dt, adding 0, 1, 2, 3 etc, casting as VARCHAR, adding '0' to the left (so that it is at least 2 chars in length) then taking the right two chars (the '0' and RIGHT operation just ensure anything under 10 have a leading '0').
It is possible to do this using dynamic SQL, however I would also consider looking at the pivot operators to see if they can achieve what you are after a lot more efficiently.
https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx

Concatenate date variable mdx

Hello guys sorry to bother again with a horrible question
I have the following mdx and I need to format the date YYYYMMDD but I am having trouble as no matter how I phrase it it wont compile on the store procedure, or if it does the resulting mdx is no good.
Heres the code I have so far, using sqlserver 2000.
set #CONSULTA = 'select [' +CONVERT(VARCHAR(8), #fecha, 112)+ '] AS [' +YYYYMMDD+ '], A.*
from (SELECT
isnull(CAST("[Measures].[Cajas Dia]" As float(18,6)),2) As cajas_dia,
isnull(CAST("[Measures].[P Redondeadas]" As int),2) As pz_redondeo
FROM openrowset(''MSOLAP'',''DATASOURCE=XXXX; Initial Catalog=XXXX; User Id=XXX;Password=XXX;'', '+ '''' + #MDX +''''+')) as A
'
I think you'd want to use style 112 instead of 122 on the CONVERT. Also not sure why you have square brackets around that in your query.
CONVERT(VARCHAR(8), #fecha, 112)
Is this what you need?
There is no style 122 and I assume you are trying to bring the date back as a literal and alias that column as YYYYMMDD?
set #CONSULTA = 'select ''' +CONVERT(VARCHAR(8), #fecha, 112)+ ''' AS [YYYYMMDD], A.*
from (SELECT
isnull(CAST("[Measures].[Cajas Dia]" As float(18,6)),2) As cajas_dia,
isnull(CAST("[Measures].[P Redondeadas]" As int),2) As pz_redondeo
FROM openrowset(''MSOLAP'',''DATASOURCE=XXXX; Initial Catalog=OLAP_HDZ; User Id=XXX;Password=XXX;'', '+ '''' + #MDX +''''+')) as A'

Help me writing this query

CREATE PROCEDURE [dbo].[sp_SelectRecipientsList4Test] --'6DBF9A01-C88F-414D-8DD9-696749258CEF','Emirates.Description','0','5'
--'6DBF9A01-C88F-414D-8DD9-696749258CEF',
--'121f8b91-a441-4fbf-8a4f-563f53fcc103'
(
#p_CreatedBy UNIQUEIDENTIFIER,
#p_SortExpression NVARCHAR(100),
#p_StartIndex INT,
#p_MaxRows INT
)
AS
SET NOCOUNT ON;
IF LEN(#p_SortExpression) = 0
SET #p_SortExpression = 'Users.Name Asc'
DECLARE #sql NVARCHAR(4000)
SET #sql='
DECLARE #p_CreatedBy UNIQUEIDENTIFIER
SELECT
Name,
POBox,
EmirateName,
TelephoneNo,
RecipientID,
CreatedBy,
CreatedDate,
ID
FROM
(
SELECT Users.Name, Users.POBox, Emirates.Description As EmirateName,
UserDetails.TelephoneNo, AddressBook.RecipientID,AddressBook.CreatedBy, AddressBook.CreatedDate,
AddressBook.ID,
ROW_NUMBER() OVER(ORDER BY '+ #p_SortExpression +') AS Indexing
FROM AddressBook INNER JOIN
Users ON AddressBook.RecipientID = Users.ID INNER JOIN
UserDetails ON Users.ID = UserDetails.UserID INNER JOIN
Emirates ON Users.EmiratesID = Emirates.ID
----WHERE (AddressBook.CreatedBy = #p_CreatedBy)
) AS NewDataTable
WHERE Indexing > '+ CONVERT(NVARCHAR(10), #p_StartIndex) +
' AND Indexing<=(' + CONVERT (NVARCHAR(10),#p_StartIndex ) + ' + '
+ CONVERT(NVARCHAR(10),#p_MaxRows)+') '
EXEC sp_executesql #sql
This query is not giving any error but also not giving any result
please help
Have you tried breaking down the statement, to check if intermediate results are as expected? That's what you do to debug a complex statement...
For example, there's a nested SELECT in there. If you commit that SELECT on its own, does it print the expected values?
Edit: There's a saying about teaching a man to fish. 'ck' and 'n8wrl' have given you fish to eat today, now please practice fishing to feed you tomorrow...
Well, a quick glance of this:
WHERE Indexing > '+ CONVERT(NVARCHAR(10), #p_StartIndex) + ' AND Indexing<=(' + CONVERT (NVARCHAR(10),#p_StartIndex ) +...
looks like you're looking for an impossible condition, not unlike this:
WHERE Indexing > 5 AND Indexing <= 5
So that might be why you're getting no rows, but this proc is ripe for SQL injection attacks too. Building SQL on the fly based on possibly-unvalidated parameters is very dangerous.
You are querying:
'WHERE Indexing > '+ CONVERT(NVARCHAR(10), #p_StartIndex) +
' AND Indexing<=(' + CONVERT (NVARCHAR(10),#p_StartIndex ) + ' + '
and then adding max rows as a string, you can do this much more easily like so:
'WHERE Indexing > '+ CONVERT(NVARCHAR(10), #p_StartIndex) +
' AND Indexing <='+ CONVERT(NVARCHAR(10),#p_StartIndex + #p_MaxRows)
EDIT
The problem with your inner WHERE is that you are passing in the parameter, you need to do
'WHERE (AddressBook.CreatedBy = ''' + CAST(#p_CreatedBy AS CHAR(36)) + ''')'
Are you sure all your joins should be inner joins?
Change sp_executesql to PRINT and see what gets generated (the poor man's debugger)
Besides what all the other people told you,
give me one good reason why you are using sp_executesql over exec? You are not using parameterized statements, you also are not protected from sql injections because you just execute the whole string
This will just bloat the procedure cache everytime this is run and some values change, you will get a new plan every time
Please take a look at Changing exec to sp_executesql doesn't provide any benefit if you are not using parameters correctly and Avoid Conversions In Execution Plans By Using sp_executesql Instead of Exec

Resources