Including list of params in OPENQUERY - sql-server

I'm trying to get the values from an external Database server executing the following code:
DECLARE #TSQL VARCHAR(8000), #VAR CHAR(2)
DECLARE #Prefixos VARCHAR(MAX);
WITH cte AS
(
SELECT DISTINCT prefixo
FROM ARH.arh.UorPos
)
SELECT #Prefixos = COALESCE(#Prefixos + ', ', '') + prefixo
FROM cte
ORDER BY prefixo
--SELECT #Prefixos --print a list of values separated by comma. eg.: 1, 2, 3
SELECT #TSQL = 'SELECT * FROM OPENQUERY(DICOI_LINKEDSERVER,''SELECT * FROM ssr.vw_sigas_diage where cd_prf_responsavel in (''''' + #Prefixos + ''''''') order by cd_prf_responsavel, codigo'
EXEC (#TSQL)
But I'm getting:
OLE DB provider "MSDASQL" for linked server "DICOI_LINKEDSERVER" returned message "ERRO: syntax error at the end of input;
No query has been executed with that handle".
Msg 7350, Level 16, State 2, Line 1
Cannot get the column information from OLE DB provider "MSDASQL" for linked server "DICOI_LINKEDSERVER".
I've researched the above links to try to resolve it:
How to concatenate text from multiple rows into a single text string in SQL server?
including parameters in OPENQUERY
Join query result to a single line of values separated by comma [duplicate]
Can anyone help me to resolve it ?
Thanks in advance.

Before running your query with EXEC, it's best to just check first how the generated SQL string will look like.
For example by selecting the variable
DECLARE #TSQL VARCHAR(8000), #VAR CHAR(2)
DECLARE #Prefixos VARCHAR(MAX);
WITH cte AS
(
SELECT DISTINCT prefixo
FROM (values ('1'),('2'),('3')) q(prefixo)
)
SELECT #Prefixos = COALESCE(#Prefixos + ', ', '') + prefixo
FROM cte
ORDER BY prefixo
SELECT #TSQL = 'SELECT * FROM OPENQUERY(DICOI_LINKEDSERVER,''SELECT * FROM ssr.vw_sigas_diage where cd_prf_responsavel in (''''' + #Prefixos + ''''''') order by cd_prf_responsavel, codigo'
select #TSQL as TSQL
-- EXEC (#TSQL)
Then you can visually check if there's something odd about it.
Or just try running that sql yourself and see if it fails or not.
From that T-SQL it returns this result :
SELECT * FROM OPENQUERY(DICOI_LINKEDSERVER,'SELECT * FROM ssr.vw_sigas_diage where cd_prf_responsavel in (''1, 2, 3''') order by cd_prf_responsavel, codigo
Notice that there's a bit to many single-quotes in that string.
When using an IN with numbers, the single-quotes are not needed.
And something is missing at the end.
... in ('+ #Prefixos +') order by cd_prf_responsavel, codigo'');';

Related

Dynamically PIVOT on ONE AND ONLY ONE column from a single TABLE

I've read multiple threads on this topic, and there does seem to be a way to do this dynamically, but I'm getting a syntax/compile error on the code.
I am trying to dynamically pull multiple rows for a temp table that simply has one column. The definition of the temp table is one field called acct_name. The challenge seems to be the "dynamics" of the fact that there will be over 50+ rows in the temp table, which is subject to change at any time.
I followed a previous poster's example, but am still getting compile/runtime errors.
I'm a rather novice SQL person, so you'll have to excuse the crudity of my code or my question.
DECLARE #idList varchar(500)
SELECT #idList = COALESCE(#idList + ',', '') + acct_name
FROM ##tmp_accts
DECLARE #sqlToRun varchar(1000)
SET #sqlToRun = '
SELECT *
FROM (
SELECT acct_name FROM ##tmp_accts
) AS src
PIVOT (
MAX(acct_name) FOR acct_name IN ('+ #idList +')
) AS pvt'
EXEC (#sqlToRun)
Does anyone have an obvious suggestion, I think it's very close to working.....
FOR EXAMPLE,
Let's say for sake of example we have the following acct_names - '12345','23456','34567','45678'.
The desire result is to return one row with 4 columns each with the respective value of acct_name. HOWEVER, the acct name is dynamic and is not known in advance, nor is the count of acct_name known in advance. A temp table is generated on the fly which determines all of the relevant acct_names for that particular run. It will vary with each run, each day that the query is run.
Thank you.....
Thru an article available thru Microsoft, the following solution does the job apporpriately.....
DECLARE
#columns NVARCHAR(MAX) = '',
#sql NVARCHAR(MAX) = '';
-- select the category names
SELECT
#columns+=QUOTENAME(acct_name) + ','
FROM
##tmp_accts
GROUP BY
acct_name;
-- remove the last comma
SET #columns = LEFT(#columns, LEN(#columns) - 1);
-- construct dynamic SQL
SET #sql ='
SELECT * FROM
(
SELECT DISTINCT acct_name
FROM
##tmp_accts
) t
PIVOT(
COUNT(acct_name)
FOR acct_name IN ('+ #columns + ')
) AS piv;';
-- execute the dynamic SQL
EXECUTE sp_executesql #sql;

passing multiple datatypes into dynamic sql-values not passing in parameterized query [duplicate]

This question already has answers here:
Dynamic SQL Not Converting VARCHAR To INT (shouldn't anyway)
(2 answers)
Closed 4 years ago.
I have a dynamic SQL query inside a stored procedure that works and gives me the correct results. But it is taking too long-because I have to compare as varchar instead of int. I believe #query variable in SQL server requires the statement to be a unicode.
Here is the dynamic sql part
ALTER PROCEDURE [dbo].[sp_GetRows]( #Id varchar(64))
AS
BEGIN
DECLARE #Query nvarchar(4000),
#Comp varchar(256)
SELECT #Comp
= STUFF((
SELECT DISTINCT ',' + char(39)+
tci.Component +char(39)
FROM TCI tci WITH(NOLOCK)
JOIN CDetail cd WITH(NOLOCK)
ON tci.ParentCId = cd.CIdentifier
WHERE tci.ParentCId = #Id
AND cd.ParentBranch IS NULL
FOR XML PATH('')),1,1,'')
SET #Query
= 'WITH CTE AS
(
SELECT '+#Id+' as ParentCId, CIdentifier as ChildCId,
a.Comp as Comp
from dbo.CD cd WITH(NOLOCK)
INNER JOIN
(SELECT DISTINCT ChildCId,Comp
FROM TCI tc WITH(NOLOCK)
WHERE ParentCId = '+ #Id + '
) a
ON cd.CIdentifier= a.ChildCId
);
EXEC (#Query)
END;
Here is the comparison-
SELECT CIdentifier FROM #tempTable temp WITH(NOLOCK)
WHERE temp.CIdentifier < '+#Id+'....
This compares as CIdentifier =1122233 instead of CIdentifier ='1122233' because dynamic SQL is not allowing me to pass it as an int. I keep getting the 'cannot convert varchar to int error'
So I used parameterized query - hoping that would enable me to pass int values.Here is the query part
SET #Query
= N';WITH CTE AS
(
......
(SELECT DISTINCT ChildCId,Comp
FROM TCI tc WITH(NOLOCK)
WHERE ParentCId = #Id
AND ChildCId + tc.Comp
NOT IN
(SELECT ChildId + Comp FROM dbo.TCI WITH(NOLOCK)
WHERE ParentId IN (SELECT CIdentifier FROM #tempTable WITH(NOLOCK)
WHERE temp.CIdentifier < #Idn
AND Comp IN ( #Comp))
)
)
)a
ON cd.CIdentifier= a.ChildId
)
SELECT * FROM CTE;'
EXEC sp_executeSQL #Query,'#Id VARCHAR(64),#Idn INT,#comp VARCHAR(256)',#Id=#Id,#Idn=#Idn,#comp =#comp
This gives me incorrect results and when I saw the execution using a trace - saw that values are not being passed onto the query. How can I get the query to pick up the variables?
Just change WHERE ParentCId = '+ #Id + ' to WHERE ParentCId = '+ cast(#Id as varchar(16)) + ' in the first query. The problem is SQL Server see's + as addition when the value is a numeric type, or date, and concatenation when it isn't. This is where you get the error from. However, when you do this, it will not make SQL Server compare it as a string literal so you don't have to worry about that. You can see this if you use PRINT (#Query) at the end instead of EXEC (#Query)
Note, this needs to be changed at the other locations you have any NUMERIC data type, like in the SELECT portion, SELECT '+ cast(#Id as varchar(16)) +'
Also, you code doesn't show where #Id value comes from, so be cautious of SQL injection here.

SQL pivot query error: Dynamic company names. Error - Unclosed quotation mark

I have a table called Xref.
Made up of columns ShaftecNo, CompNo, CompName.
I am trying to write a pivot query that displays [ShaftecNo],[CompNo] and then [CompName] as columns). Resulting in the following format
Code used in my stored procedure is as follows.
declare #sql nvarchar(max);
-- generate the column names
select #sql = coalesce(#sql + ',', '') + QuoteName([CompName])
from (select DISTINCT CompName from [Xrefs] WHERE CompName LIKE '[a-z]%') T;
-- replace the column names into the generic PIVOT form
set #sql = REPLACE('
select ShaftecNo, :columns:
from (SELECT ShaftecNo,CompNo,CompName FROM Xrefs INNER JOIN Product ON Xrefs.ShaftecNo COLLATE Latin1_General_CI_AS = Product.KeyCode) p
pivot (max(CompNo) for CompName in (:columns:)) as pv',
':columns:', #sql)
-- execute for the results
exec (#sql)
Please note, the LIKE command used will work if i change it to [a-c] ( only [CompName]'s that starts with a-c range) if i do a larger range like [a-r] it errors.
Msg 105, Level 15, State 1, Line 4
Unclosed quotation mark after the character string 'ALFAROME'.
Msg 102, Level 15, State 1, Line 4
Incorrect syntax near 'ALFAROME'.
The errors change for different ranges. If i take the like out completely the the query works BUT it misses out company names (i.e .Brake Engineering).
Can anyone help
It sounds like your CompName field has values that have contain single quotes, so you will need to remove/replace them when building your #sql value:
declare #sql nvarchar(max);
-- generate the column names
select #sql = coalesce(#sql + ',', '') + QuoteName(replace([CompName],'''',''))
from (select DISTINCT CompName from [Xrefs] WHERE CompName LIKE '[a-z]%') T;
-- replace the column names into the generic PIVOT form
set #sql = REPLACE('
select ShaftecNo, :columns:
from (SELECT CompNo,replace(CompName,'''''''','''') as CompName FROM a INNER JOIN Product ON Xrefs.ShaftecNo COLLATE Latin1_General_CI_AS = Product.KeyCode) p
pivot (max(CompNo) for CompName in (:columns:)) as pv',
':columns:', #sql)
-- execute for the results
exec (#sql)
Thanks for all your help. The PRINT #SQL command worked like a dream. (Thank you Nick.McDermaid) .
The problem was a random unicode ascii character - 160. Which i had to get by using ...
SELECT distinct Compname, ASCII(SUBSTRING(Compname,LEN(Compname)-1,LEN(Compname))) from [Xrefs_Temp].
Then i replaced it with blanks and it worked.
Thanks again

How to convert row to column in SQL?

I have a stored procedure (join two tables and select where condition #GID), a want to convert table result from rows to columns. I use a dynamic pivot query.
My stored procedure:
After I try using pivot
I want result like this:
GROUP_MOD_ID ADD EDIT DELETE ETC...
---------------------------------------
G02 1 1 0 ....
Can you give me some advice about this ?
Thank you.
It's because you're using the batch delimiter to separate your queries. This means the scope of #GID is incorrect. Remove the semi colon after:
DECLARE #pivot_cols NVARCHAR(MAX);
You don't need to use batch delimiters in this case. The logical flow of the procedure means you can omit them without any problems.
EDIT:
Here's the edited code that I've devised:
ALTER PROCEDURE GET_COLUMN_VALUE #GID CHAR(3)
AS
BEGIN
DECLARE #PivotCols NVARCHAR(MAX)
SELECT #PivotCols = STUFF((SELECT DISTINCT ' , ' + QUOTENAME(B.FUNCTION_MOD_NAME)
FROM FUNCTION_GROUP AS A
JOIN FUNCTION_MOD B
ON A.FUNCTION_MOD_ID = B.FUNCTION_MOD_ID
WHERE A.GROUP_MOD_ID = #GID
FOR XML PATH (' '), TYPE).value(' . ', 'NVARCHAR(MAX) '), 1, 1, ' ')
DECLARE #PivotQuery NVARCHAR(MAX)
SET #PivotQuery = '
;WITH CTE AS (
SELECT A.GROUP_MOD_ID, B.FUNCTION_MOD_NAME, CAST(ALLOW AS BIT) AS ALLOW
FROM FUNCTION_GROUP AS A
JOIN FUNCTION_MOD AS B
ON A.FUNCTION_MOD_ID = B.FUNCTION_MOD_ID)
SELECT GROUP_MOD_ID, '+#PivotCols+'
FROM CTE
PIVOT (MAX(ALLOW) FOR FUNCTION_MOD_NAME IN ('+#PivotCols')) AS PIV'
PRINT #PivotQuery
EXEC (#PivotQuery)
END
EDIT2:
You should execute this stored procedure like so:
EXEC GET_COLUMN_VALUE #GID='G02'

how to add '+' sign in dynamic sql

I hope you can help me with this..I want to get the sum of all rows in the result query.. this is the sql query I have so far..
DECLARE #earninglist varchar(1000)
Set #earninglist=STUFF((SELECT DISTINCT '],['
+LTRIM([Description]) FROM
PR_Earnings
ORDER BY '],[' + LTRIM([Description])
FOR XML PATH('')
), 1, 2, '')+']'
Declare #sql varchar(max)
set #sql='Select '+#earninglist+' from earnings;'
exec(#sql);
say that earning list contains this fields: 'Cola','Incentives' How can I declare #earninglist so that I can get this following query:
set #sql='Select Coalesce([Cola],0)+Coalesce([Incentives],0) as total from earnings'
hope you can help me..thanks alot.
You should be aware that your script is open to sql-injections. Description can be written to drop your tables.
DECLARE #earninglist varchar(1000)
Set #earninglist=STUFF((SELECT DISTINCT '],0),coalesce(['
+LTRIM([Description]) FROM
PR_Earnings (description)
ORDER BY '],0),coalesce([' + LTRIM([Description])
FOR XML PATH('')
), 1, 5, '')+'], 0)'
You can test with this script:
SELECT STUFF((SELECT DISTINCT '],0),coalesce(['
+LTRIM([Description]) FROM
(values ('cola'),('Incentives')) PR_Earnings (description)
ORDER BY '],0),coalesce([' + LTRIM([Description])
FOR XML PATH('')
), 1, 5, '')+'], 0)'
Result:
coalesce([cola],0),coalesce([Incentives], 0)
I'm sure there are other much more elegant ways but...why not just replace the first occurrence of ")" with ")+" in the variable?

Resources