Reading specific value with Openrowset in SQL Server 2016 - sql-server

The aim here is to read a specific value from a different server and store the return value in a local parameter for use later.
Here is the error code:
Msg 102, Level 15, State 1, Line 3
Incorrect syntax near 'Alarm'.
Here is the code I have tried:
declare #sql_string nvarchar(400);
declare #inhostnamn nvarchar(100) = 'BLUE65\SQLEXPRESS'
declare #inuser nvarchar(50) = 'dev1'
declare #password1 nvarchar(50) = 'dev1'
declare #database nvarchar(100) = 'Test_destroy'
declare #count_posts varchar(10)
declare #tabellnamn varchar(50) = 'Alarms'
declare #last_read_alarm varchar(30)
set #tabellnamn = 'Logg'
set #sql_string = N'set #last_read_alarm1 = cast(last_read as nvarchar(30)) select * from openrowset (''SQLNCLI'', ''Server='+#inhostnamn+';UID='+#inuser+';Pwd='+#password1+';Database='+#database+';Persist Security Info=True'',''select Last_ID FROM '+#database +'.dbo.Logg where Tables_sql=''Alarm'' '')';
print 'string =' + #sql_string;
exec sp_executesql #sql_string, N'#last_read_alarm1 varchar(30) OUTPUT', #last_read_alarm1=#last_read_alarm OUTPUT;
select #last_read_alarm
print #last_read_alarm;
Now I am stuck. I cannot see the error I have made, and am hoping for a couple of different eyes.

Thanks to Andrei Odegov for great assistance. It helped putting 4 ' on each side.
The correct code would be in my case now:
set #sql_string = N'select #last_read_alarm= (select * from openrowset (''SQLNCLI'', ''Server='+#inhostnamn+';UID='+#inuser+';Pwd='+#password1+';Database='+#database+';Persist Security Info=True'',''select Last_ID FROM '+#database +'.dbo.Logg where Tables_sql='''''+#tmp_str+''''' ''))';
So the answer from the query will now end up in local variable #last_read_alarm.

Related

Return variable using OPENQUERY

I am trying to make a simple function that reads a table from an ORACLE database and returns a sequence number. I would either like to return it directly or store the value inside of #cwpSeq and return that to the calling program.
Right now I am getting error:
RETURN statements in scalar valued functions must include an argument.
Can anyone assist me.
create function dbo.get_cwpSeq_from_oracle(#COIL nvarchar(100) )
returns int as
begin
DECLARE #cwpSeq int, #SQL nvarchar(1000);
set #SQL = N'select * from openquery(DEV, 'select cwp_seq from apps.custom_wip_pieces where lot_number = ''' + #COIL + '')';
return execute sp_executesql #SQL;
end;
As already mentioned, in this case you should use a procedure with an output parameter instead of a function. If you want to fully execute the query on the Oracle linked server side and return some value after that, I would suggest using dynamic as follows:
Create Or Alter Procedure dbo.get_cwpSeq
#COIL nvarchar(100),
#cwp_seq Int Output
As
Declare #QueryText nVarChar(max)
Select #QueryText = 'Select #cwp_seq=cwp_seq
From Openquery(DEV,
''Select cwp_seq
From apps.custom_wip_pieces
Where lot_number= ''''' + #COIL + ''''''') As Ora';
Execute sp_executesql #QueryText, N'#COIL nvarchar(100), #cwp_seq Int Output', #COIL = #COIL, #cwp_seq = #cwp_seq Output
As far as I understand in your case:
Linked server is "DEV", Owner of the table is "apps".

SQL Server Stored Procedure insert query with given parameters

first of all, sorry for my English,
I am a newbie in stored procedure, so i'm seek for a help on it.
I have a project that need me to create a SP for a configurable table name and column name. I've manage to pass the table name and column name value from vb/vb.net and now i'm stuck on SP, below are sample of my code.
example :
frmTblname = table_a
frmClmnName = clm_A1, clm_A2, clm_A3, clm_A4, clm_A5,
toTblName = table_b,
toClmnName = clmn_b1,clmn_b2, clmn_b3, clmn_b4, clmn_b5
from vb/vb.net Rslt = ConnectionExec.RunSP(con, "sp_configurable_insert", frmTblname, frmClmnName, toTblName, toClmnName)
how to add that into SQL insert query?
Here are my SP
CREATE procedure [dbo].[sp_configurable_insert] #fromTable nvarchar(50),#fromColumn nvarchar(4000),#toTable nvarchar(50),#toColumn nvarchar(4000)
I've tried this but it seems not giving any result.
set #Query1 = 'insert into '+#toTable+'('+quotename(#toColumn)+')
select top 20 '+#fromColumn+'
from '+#fromTable+'
can anyone help me, please?
Thanks :)
Things to change:
quotename(#toColumn) will return '[clmn_b1,clmn_b2, clmn_b3, clmn_b4, clmn_b5]' which is not correct. Remove quotename() or set #toColumn = '[clmn_b1], [clmn_b2], [clmn_b3], [clmn_b4], [clmn_b5]'.
your query statement is unfinished.
Stored procedure (with correct syntax):
CREATE procedure [dbo].[sp_configurable_insert]
#fromTable nvarchar(50),
#fromColumn nvarchar(4000),
#toTable nvarchar(50),
#toColumn nvarchar(4000)
AS
BEGIN
DECLARE
#stm nvarchar(max),
#err int
SET #stm =
N'insert into '+#toTable+' ('+#toColumn+') select top 20 '+#fromColumn+' from '+#fromTable
EXEC #err = sp_executesql #stm
IF #err <> 0 BEGIN
RETURN #err
END
RETURN 0
END
you need to add EXECUTE(#Query1) to your SP and it will work
Add at the end of your query:
exec sp_executesql #Query1
So it should look like:
set #Query1 = 'insert into '+#toTable+'('+quotename(#toColumn)+')
select top 20 '+#fromColumn+'
from '+#fromTable+'
exec sp_executesql #Query1
So pay attention that #Query1 is incomplete or contains error coz quotes is unbalanced.

Dynamical ms sql query

I have problems with my dynamical ms sql query. Can someone help me. Here is my code. Problem is inside the OPENQUERY, near '1033'
DECLARE #sql nvarchar(max);
DECLARE #server nvarchar(255) = (SELECT [Value] FROM [WarehouseMgmt].[SyncConfig] WHERE [Key] = 'ReportServerLinkedServer')
DECLARE #database nvarchar(255) = (SELECT [Value] FROM [WarehouseMgmt].[SyncConfig] WHERE [Key] = 'ReportServerDatabase')
SET #sql = 'MERGE [WarehouseMgmt].[DimReportServerReports] AS DRSR
USING (SELECT ItemId,Name FROM OPENQUERY('+#server+',''SELECT ItemId,Name FROM '+#database+'.[dbo].[Catalog] WHERE Type=2 AND Name NOT LIKE ''1033%'' AND Path NOT LIKE ''/Reports/%Subs'')
) AS CATALOG
ON (DRSR.[SourceOrigId] = [Catalog].[ItemId])
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
[SourceOrigId],
[ReportName],
SyncExecId
)
VALUES
(
[Catalog].[ItemId],
ISNULL([Catalog].[Name],''<UNKNOWN>''),
#SyncExecId
)
OUTPUT
[Catalog].[ItemId],
[Catalog].[Name]
INTO #NewReportServerReports;'
EXEC sp_executesql #sql,N'#SyncExecId int',#SyncExecId
Error code is:
Msg 50000, Level 11, State 1, Procedure WriteJobLog, Line 101 Error
writing job log: Line #90: [ERR] #2: Incorrect syntax near '1033'.
Added few quotes. Try this.
SET #sql = 'MERGE [WarehouseMgmt].[DimReportServerReports] AS DRSR
USING (SELECT ItemId,Name FROM OPENQUERY('+#server+',''SELECT ItemId,Name FROM '+#database+'.[dbo].[Catalog] WHERE
Type=2 AND Name NOT LIKE ''''1033%'''' AND Path NOT LIKE ''''/Reports/%Subs'''''')
) AS CATALOG
ON (DRSR.[SourceOrigId] = [Catalog].[ItemId])
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
[SourceOrigId],
[ReportName],
SyncExecId
)
VALUES
(
[Catalog].[ItemId],
ISNULL([Catalog].[Name],''<UNKNOWN>''),
#SyncExecId
)
OUTPUT
[Catalog].[ItemId],
[Catalog].[Name]
INTO #NewReportServerReports;'
--print #sql
EXEC sp_executesql #sql,N'#SyncExecId int',#SyncExecId

Cannot locate find function called in a procedure

I am quite new to SQL Server. I have an issue where we have a stored procedure called sys.sp_MSallocate_new_identity_range (see part of logic below). It makes reference to two functions neither of which I can locate.
if (**sys.fn_MSmerge_isrepublisher**(#artid)=0)
begin
declare #publisher_max_used numeric(38,0)
declare #pubid uniqueidentifier
declare #pub_ranges_needed tinyint
declare #pub_refresh_constraint bit
select #pubid = subid, #publisher_max_used = max_used from dbo.MSmerge_identity_range
where artid = #artid and is_pub_range = 1 and (**sys.fn_MSmerge_islocalpubid**(subid)=1)
if #pubid is NULL
begin
raiserror(20663, 16, -1)
return 1
end
Running the stored prcoedure with appropriate parameters - returns a result :
declare #p4 smallint
set #p4=2
declare #p5 numeric(38,0)
set #p5=31001
declare #p6 numeric(38,0)
set #p6=32001
declare #p7 numeric(38,0)
set #p7=32001
declare #p8 numeric(38,0)
set #p8=33001
exec sys.sp_MSallocate_new_identity_range 'B551D87F-5457-2102-9E6A-DD4EB44B1DD1','4EB5E2D0-3FC1-4D77-B894-5D57C433D0B2',2,#p4 output,#p5 output,#p6 output,#p7 output,#p8 output,N'dev_02',N'PPC04 - 21a535007fd8',N'My Documents\Assets\assets.sdf'
select #p4, #p5, #p6, #p7, #p8
i.e This works and returns a result. All Good - but I cannot locate the functions embedded within the stored procedure i.e. sys.fn_MSmerge_isrepublisher or sys.fn_MSmerge_islocalpubid.
I have looked in sys.objects and sys.all_objects where name like '%fn_MSmerge%'.
I have managed to trace the SQL and the trace gives an ObjectID and I can see the statement executing. The trace tells me it is a function -
20038 - FN - and gives me an objectid of 563464549 - but cannot find by looking in sys.objects for the database
Any help/advice gladly accepted.
These object definitions do seem to be hidden. If you connect via the DAC and run
SELECT OBJECT_DEFINITION(OBJECT_ID('sys.fn_MSmerge_islocalpubid')) AS
[processing-instruction(x)],
OBJECT_DEFINITION(OBJECT_ID('sys.fn_MSmerge_isrepublisher')) AS
[processing-instruction(y)]
FOR XML PATH('')
you can see them though. The definitions for my version of SQL Server are as below
create function sys.fn_MSmerge_islocalpubid (#pubid uniqueidentifier)
returns bit
as
begin
declare #publisher_db sysname
declare #publisher sysname
select #publisher_db = publisher_db, #publisher = publisher
from dbo.sysmergepublications
where pubid = #pubid
if #publisher_db is NULL or #publisher is NULL
return 0
if #publisher_db = db_name() and UPPER(#publisher) = UPPER(publishingservername())
return 1
return 0
end
create function sys.fn_MSmerge_isrepublisher (#artid uniqueidentifier)
returns bit
as
begin
if exists (select pubid from dbo.sysmergearticles where artid = #artid and (sys.fn_MSmerge_islocalpubid(pubid) = 0))
return 1
return 0
end

Parameterizing XPath for modify() in SQL Server XML Processing

Just like the title suggests, I'm trying to parameterize the XPath for a modify() method for an XML data column in SQL Server, but running into some problems.
So far I have:
DECLARE #newVal varchar(50)
DECLARE #xmlQuery varchar(50)
SELECT #newVal = 'features'
SELECT #xmlQuery = 'settings/resources/type/text()'
UPDATE [dbo].[Users]
SET [SettingsXml].modify('
replace value of (sql:variable("#xmlQuery"))[1]
with sql:variable("#newVal")')
WHERE UserId = 1
with the following XML Structure:
<settings>
...
<resources>
<type> ... </type>
...
</resources>
...
</settings>
which is then generating this error:
XQuery [dbo.Users.NewSettingsXml.modify()]: The target of 'replace' must be at most one node, found 'xs:string ?'
Now I realize that the modify method must not be capable of accepting a string as a path, but is there a way to accomplish this short of using dynamic SQL?
Oh, by the way, I'm using SQL Server 2008 Standard 64-bit, but any queries I write need to be compatible back to 2005 Standard.
Thanks!
In case anyone was interested, I came up with a pretty decent solution myself using a dynamic query:
DECLARE #newVal nvarchar(max)
DECLARE #xmlQuery nvarchar(max)
DECLARE #id int
SET #newVal = 'foo'
SET #xmlQuery = '/root/node/leaf/text()'
SET #id = 1
DECLARE #query nvarchar(max)
SET #query = '
UPDATE [Table]
SET [XmlColumn].modify(''
replace value of (' + #xmlQuery + '))[1]
with sql:variable("#newVal")'')
WHERE Id = #id'
EXEC sp_executesql #query,
N'#newVal nvarchar(max) #id int',
#newVal, #id
Using this, the only unsafe part of the dynamic query is the xPath, which, in my case, is controlled entirely by my code and so shouldn't be exploitable.
The best I could figure out was this:
declare #Q1 varchar(50)
declare #Q2 varchar(50)
declare #Q3 varchar(50)
set #Q1 = 'settings'
set #Q2 = 'resources'
set #Q3 = 'type'
UPDATE [dbo].[Users]
SET [SettingsXml].modify('
replace value of (for $n1 in /*,
$n2 in $n1/*,
$n3 in $n2/*
where $n1[local-name(.) = sql:variable("#Q1")] and
$n2[local-name(.) = sql:variable("#Q2")] and
$n3[local-name(.) = sql:variable("#Q3")]
return $n3/text())[1]
with sql:variable("#newVal")')
WHERE UserId = 1
Node names are parameters but the level/number of nodes is sadly not.
Here is the solution we found for parameterizing both the property name to be replaced and the new value. It needs a specific xpath, and the parameter name can be an sql variable or table column.
SET Bundle.modify
(
'replace value of(//config-entry-metadata/parameter-name[text() = sql:column("BTC.Name")]/../..//value/text())[1] with sql:column("BTC.Value") '
)
This is the hard coded x path: //config-entry-metadata/parameter-name ... /../..//value/text()
The name of the parameter is dynamic: [text() = sql:column("BTC.Name")]
The new value is also dynamic: with sql:column("BTC.Value")

Resources