I am building a query using the JPA's CriteriaBuilder to call the SQL Server exist function to find data based on an XML field and it is failing to run due to a The argument 1 of the XML data type method "exist" must be a string literal. error.
I traced the SQL generated and get the same error when I try the query in SQL Server Management Studio. I've simplified the SQL to the following for reference
declare #p1 int
set #p1=NULL
exec sp_prepexec #p1 output,
N'#P0 varchar(8000)',
N'select id, name from mytable where xmlfield.exist(#P0)=1 order by id desc',
'true()'
select #p1
The interesting thing is when I try the query by itself, it runs fine and returns the results.
select id, name from mytable where xmlfield.exist('true()')=1 order by id desc;
Any thoughts on why the generated parameterized SQL statement generated does not work?
As the error message states, the value passed into the "exist" function must be a string literal. The example given is trying to pass a variable into the function, but then when you're running the query by itself it works just fine because you're passing in a string literal.
For example...
DECLARE #xml XML = '';
DECLARE #P0 NVARCHAR(500) = 'true()';
SELECT #xml.exist(#P0) -- will not work
SELECT #xml.exist('true()') -- will work
For the longest time I thought this made these functions worthless because I didn't know you could use variables within the string literal. Here is an example:
DECLARE #xml XML = '<root><item id="1" /><item id="2"><test /></item></root>';
DECLARE #item_id INT;
SET #item_id = 1; -- "test" element does not exist
SELECT #xml.exist('/root/item[#id=sql:variable("#item_id")]/test')
SET #item_id = 2; -- "test" element does exist
SELECT #xml.exist('/root/item[#id=sql:variable("#item_id")]/test')
Related
I am creating an Execute SQL task in SSIS 2016 which calls an insert stored procedure. I am trying to return the id of the newly created row in the output parameter but facing the following error.
No result rowset is associated with the execution of this query
I had set the SQL Server Profiler on to see what was generated and it was as follows
declare #p4 int
set #p4=NULL
exec sp_executesql N'Exec [dbo].[InsertPkgAudit] #P1,#P2',N'#P1 varchar(16),#P2 int OUTPUT','CoreReferenceETL',#p4 output
select #p4
If I execute the following it manually it works
DECLARE #auditId INT;
EXEC [dbo].[InsertPkgAudit] #packageName = 'CoreReferenceETL', #auditId = #auditId OUTPUT;
PRINT #auditId;
So it is clear that the stored procedure is fine but some problem with the way its called in SSIS. Could somebody help ?
The Execute SQL task contains the following statement
Exec [dbo].[InsertPkgAudit] #packageName =?, #auditId = ?
The parameter mapping is as follows
The result pane is as follows
The stored procedure is as follows:
CREATE Procedure [dbo].[InsertPkgAudit]
#packageName varchar(100),
#auditId int output
AS
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[PkgAudit] ([PackageName], [StartTime])
VALUES (#packageName, GETDATE());
SET #auditId = SCOPE_IDENTITY();
END
The table structure is as follows
You have told SSIS that your procedure returns a result set. But it doesn't. It populates an OUTPUT parameter instead.
You can either change your proc to return a resultset, or you can modify the Execute task and
Specify No Result Set
Change the query to this:
`Exec [dbo].[InsertPkgAudit] #packageName =?, #auditId = ? OUTPUT`
I just had a similar issue and while looking for some sort of solution I came across this old post. I wasn't able to find the solution online but, here is how I resolved my issue. I hope this helps folks in the future.
If you really need to get the data passed via RowSet, you will need to select as
'ColumnName'.
Declare #fname varchar(50)
Declare #lname varchar(50)
set #fname ='John'
set #lname= 'Doe'
select #fname, #lname--without column name
select #fname as 'firstName', #lname as 'LastName'--with column name
Here is how they would show up in the results.
You can now map the result to proper variable.
I have a linked server that I have to fetch data from. I'm joining on a table that I expect very few rows from. The query is below, and seems to be returning all of the rows to the original server to do the sort there.
I'm looking for a way to tell the query to filter on the target machine, with a query hint or something else.
Query
INSERT INTO #DealerHierarchy(DealerId, Level)
SELECT cd.ParentId, cd.Level
FROM [dbo].[AssignedDealer] ad
JOIN [nlsdb].[nls].[dbo].[vw_parentDealers] cd ON cd.RootId = ad.DealerId
WHERE ad.UserId = #userId
AND ad.IsActive = 1
AND (#DealerId IS NULL OR ad.DealerId = #DealerId)
When I add the following line, it seems to change and only send back the needed rows
and cd.RootId = 72311
I have tried moving out the local query into a separate temp table, and then select from the view WHERE DealerId IN (select from temp table) but it still runs slowly. Adding the REMOTE hint in the JOIN also does nothing.
Query plan:
https://www.brentozar.com/pastetheplan/?id=r1iazaaFZ
Slow code executed on linked server
declare #p1 int
set #p1=7
exec sp_prepexec #p1 output,N'#P1 numeric(10)',N'SELECT "Tbl1007"."ParentId" "Col1010","Tbl1007"."Level" "Col1011" FROM "nls"."dbo"."vw_parentDealers" "Tbl1007" WHERE #P1="Tbl1007"."RootId"',72311
select #p1
Fast code executed on linked server
declare #p1 int
set #p1=10
exec sp_prepexec #p1 output,NULL,N'SELECT "Tbl1007"."ParentId" "Col1010","Tbl1007"."Level" "Col1011" FROM "nls"."dbo"."vw_parentDealers" "Tbl1007" WHERE "Tbl1007"."RootId"=(72311.)'
select #p1
You can force a specific query to be run on the remote database by using OPENQUERY. OPENQUERY doesn't accept a parameter, so you can make it dynamic by further wrapping it in EXEC.
Example
DECLARE #SearchString NVARCHAR = ...
DECLARE #OpenQueryString NVARCHAR = 'SELECT * FROM OPENQUERY(remotedb, ''' + #SearchString + ''')'
EXEC (#OpenQueryString)
I do not have access to sp's, but I have created a dynamic query that is going to accept a multi-valued parameter, pass it along to a variable, which is then going to be used in the query. Short example of my query.
DECLARE #Parameter2 varchar(200)
SET #Parameter2 = #Parameter1
SELECT personID from foo where filename IN (#Parameter2)
I have a report Parameter for #Parameter1 that will allow multiple values, which will be coming from another query from a dataset. I can pass a single filename from #Parameter1 to #Parameter2 with no issue, but when selecting multiple ones, I get the "invalid syntax at ...',' because the parameters are passed like this 'filename1,filename2,filename3'.
How to I parse these multiple parameters from #Parameter1 to #Parameter2 so it can be used in the query without a stored procedure? I have tried looking in different topics here and splitting the #Parameter1 by "," and joining the variable in the dataset properties, but I am still getting either the invalid syntax error or declaring a scalar variable error.
I don't have much experience in SQL Server, but it seems difficult to split the strings after they have been selected in the preview, without the strings passing through an sp first.
Since you can do DYNAMIC SQL, consider the following
DECLARE #Parameter1 varchar(200) = 'filename1,filename2,filename'
DECLARE #Parameter2 varchar(200) = ''''+Replace(#Parameter1,',',''',''')+''''
Declare #SQL varchar(max) = 'SELECT personID from foo where filename IN ('+#Parameter2+')'
Exec(#SQL)
The Generated SQL Looks like This:
SELECT personID from foo where filename IN ('filename1','filename2','filename')
I have a SSRS report which accepts a parameter (Country_Name).
This is a weekly report and needs to be generated automatically by triggering the SQL agent job. So, I have created a data driven subscription for this report and created a SSIS package to generate the report from SQL agent job.
Now the problem is : Since it is a automated report, there is no interface to pass the parameter to report. So, I have created a table to hold the list of parameters to be passed and the path to place the generated report.
Table will have 2 columns (Country_Name & Report_Path) and hold values like (India \AB123C\India) (China,\ABC\China) etc.
Depending on the parameter passed, location of the report will change. So, I used looping in data driven subscription query to get the parameter and path. Though there are multiple parameters and path for that respective parameter are returned by the query, it is picking only the first result set and generates report only for the first parameter and its specified location.
I unable to find out the solution for this. Please find the below query I have used for your reference. It would be great if I can get a solution for this.
DECLARE #MinCount INT = 1
DECLARE #Country VARCHAR(100)
DECLARE #Path VARCHAR(MAX)
DECLARE #RecordCount INT
DECLARE #CurrentDate VARCHAR(10)
DECLARE #CountryList Table (ID INT Identity(1,1),Country_Name Varchar(100),Report_path Varchar(max))
SET #RecordCount = (SELECT COUNT(*) FROM Country_List)
WHILE (#MinCOunt < = #RecordCount)
BEGIN
SET #Country = (Select Country_name from Country_List WHere ID = #MinCOunt)
SET #Path = (Select Report_Path from Country_List WHere ID = #MinCOunt)
SET #CurrentDate = ( SELECT CONVERT(char(10), GetDate(),126) as currentSysDate)
Delete from #CountryList
insert into #CountryList (Country_Name,Report_path) Values (#Country,#Path)
select 'Country_Details ' +
#CurrentDate as filename
,'Excel' as RenderFormat
, (select Name from Master where
Reference_Name = 'USER_NAME'
) as sqlUserId
,( select Value from Master where
Reference_Name = 'PASSWORD'
) as sqlPwd , (Select Country_Name from #CountryList) AS Issue_Country,
(Select Report_path from #CountryList) AS filePath_cfonereports
SET #MinCOunt = #MinCOunt + 1
END
I have resolved this issue now by using a different approach rather than using looping in subscription code. I created a reference table to store to the list of parameters as well as the corresponding path. Since this report is called from a SSIS package, I have used a variable to get the list of parameters from the reference table and a foreach loop container with Execute SQL task to pass one parameter from variable at a time and invoke the subscription. So that the report will be generated for that parameter passed and in the path specified. This foreach loop container will loop n times based on the count of parameters in the variable
I have used sp_addlinkedserver to access the remote machines db now i am writing queries explicitly on database like,
select * from [server\instance].database.owner.tablename
Now with this,
[Server\instance] : this has to be provided explicitly
[database] : can we find databases on specified instance using query like ms_ForEachDB ?
[owner] : Can we find the database owner name using query ?
If these values are found using queries do we need to use EXEC() to execute this or we can still achieve it using nice queries ?
Thanks all,
The "nice" format you mention is simply a 4 part object reference.
select * from [server\instance].database.owner.tablename
3 part
select * from database.owner.tablename
2 part
select * from owner.tablename
If you want to dynamically change any of the server, db or schema values then you have one option:
EXEC (#sqlstring)
However, if you only access stored procs remotely...
DECLARE #RemoteSP varchar(500)
SET #RemoteSP = '[server\instance].database2.schema.proc2'
EXEC #RemoteSP #p1, #p2, #p3 OUTPUT
SET #RemoteSP = '[server\instance].database1.schema.proc1'
EXEC #RemoteSP #p4, #p5, #p6 OUTPUT
However, changing the components of the object reference makes no sense arguably: if you know you're going to query a table then just call that table in that database...
you should make a query string and then run it by exec() function.
getting server name :
SELECT ##SERVERNAME
getting current db name :
SELECT DB_NAME() AS DataBaseName
You do not have to use EXEC you could use something like select * from openquery(MyLinkedServer,#sql) THough i prefer EXEC(#sql) AT MyLinkedServer
But all work
If it happens that you need to use some sort of variable in your arguments(e.g. collect remote's server updates since yesterday):
DECLARE #yesterday NVARCHAR(20) = '2016-09-23 08:16:20';
DECLARE #sql NVARCHAR(MAX) = N'SELECT * FROM database.targetTable AS origin
WHERE origin.columnWithDateTime >'''+#yesterday+''';';
PRINT #sql;
EXEC(#sql) AT linkedServer
______
Where:
database.targetTable : For some reason SSMS 2008 R2 returns error if you describe it as [database].[targetTable], and i don't know why that happens.
#yesterday: Is the variable you want to insert (this case, a string containing datetime-like element)
PRINT #sql: Just to verify if the quotes are correctly placed.
columnWithDateTime: Should be a column with datetime format (e.g. "timestamp", or similar to the #yesterday variable format.
"OPENQUERY does not accept variables for its arguments.": See Here (MSDN: OPENQUERY (Transact-SQL)).