Call DB2 stored procedure from SQL Server 2008 linked server - sql-server

I have a linked server from SQL Server 2008 to DB2. The linked server uses the IBM Drivers and not the Microsoft ones.
So this works from SQL Server:
exec ('call RERTEBT.GET_DEFINITION (69,'''','''')') AT MyLinkedDB2Server
This also works using openQuery... which is returning different data from another table
select
RPMG_ETY_CD,
ROW_CU_DATA_IN,
ROW_EF_DT,
ROW_XPR_DT,
RPMG_ETY_NM
from
OPENQUERY
(MyLinkedDB2Server,
'select
RPMG_ETY_CD,
ROW_CU_DATA_IN,
ROW_EF_DT,
ROW_XPR_DT,
RPMG_ETY_NM
from RERTEBT.V1RERRMM')
However I cannot get a select to return data with the DB2 Sproc
This fails -
SELECT FLT_DFN_ID, FLT_SRC_DFN_NO, FLT_VRSN_NO, FLT_STAT_CD, FLT_TY_CD, FLT_NAME
FROM OPENQUERY (MyLinkedDB2Server,
'call RERTEBT.GET_DEFINITION 69,'''','''')')
Has anyone any idea on how to call a DB2 stored procedure from SQL Server Linked server and return the data or can this be done. I read somewhere the DB2 cant do this but haven't seen any real documentation on it.
Thanks D

More explanation for Josef's answer:
You need to right-click the linked server's "properties"
then -> "Server option"
The "RPC" and "RPC Out" option in the right pane need to be TRUE
-- edited -- I can't comment on the answer yet (don't have 50 rep)

Your should be able to do this:
EXEC ('{CALL RERTEBT.GET_DEFINITION (69,'''','''')}') AT MyLinkedDB2Server;
Or even cleaner with passing variables
EXEC ('{CALL RERTEBT.GET_DEFINITION (?,?,?)}', 69, '', '') AT MyLinkedDB2Server;

Related

SQL to SAS ODBC connection - truncation of NVARCHAR(max) but getting ERROR: The option dbtype is not a valid output data set option

I have a table stored in SQL Server Management Studio version 15.0.18369.0 and I have a working and established ODBC connection to SAS language program World Programming Software version 3.4.
Previous import/reading of this data has been successful but the operator of the SQL server may have recently converted their data type to NVARCHAR(max). It may also be due to a driver change (I got a new laptop and reinstalled what I thought was the exact same OBDC for SQl driver as I had before but who knows) I have 64-bit ODBC Driver 17 for SQL server.
The VARCHAR(max) type in SQL causes the data to only be 1 character long in every column.
I have tried to fix it by:
Adding the DB max text option to libname
libname odbclib odbc dsn="xxx" user="xxx" password="xxx" DBMAX_TEXT=8000;
This did nothing so I also tried to add DB type option:
data mydata (dbtype=(mycol='char(25)')) ;
set odbclib.'sql data'n
run;
And I get ERROR:
The option dbtype is not a valid output data set option.
I have also tried DBSASTYPE, and putting both options in the set statement and this yields the same error.
I also tried with proc SQL:
proc sql noprint;
CONNECT TO ODBC(dsn="xxx" user="xxx" password="xxx"); create table
extract(compress=no dbsastype=(mycol='CHAR(20)')) as select * from
connection to odbc ( select * from dbo.'sql data'n
); disconnect from odbc; quit;
And I get
NOTE: Connected to DB: BB64 (Microsoft SQL Server version 12.00.2148)
NOTE: Successfully connected to database ODBC as alias ODBC. 3915
create table extract(compress=no
dbsastype=(mycol='CHAR(20)')) as 3916 select *
from connection to odbc 3917 ( 3918 select *
from dbo.'sql data'n ERROR: The option dbsastype is not a valid
output data set option 3919 3920 ); 3921
disconnect from odbc; NOTE: ERRORSTOP was specified. The statement
will not be executed due to an earlier error NOTE: Statements not
executed because of errors detected 3922 quit;
One thing to try would be putting the DBTYPE or DBSASTYPE in the right place.
data mydata;
set odbclib.'sql data'n(dbtype=(mycol='char(25)'));
run;
It is an option that would go on the "set" not the "data" line.
I would also encourage you to contact the developers, as it seems like this is a bug in their implementation; or perhaps try a different ODBC SQL driver.
Maybe a workaround in the meanwhile is to use CONVERT in the passthrough?
proc sql noprint;
CONNECT TO ODBC(dsn="xxx" user="xxx" password="xxx"); create table
extract as select * from
connection to odbc ( select a,b,c,convert(NCHAR(20),mycol) from dbo.'sql data'n
); disconnect from odbc; quit;

How to load data in different servers

I am designing an ETL project on SSIS and I want it to be dynamic. I will use this project for many customers therefore I will query these extractions against different servers.
For example, I have this query in a step with "execute SQL task" component :
INSERT DataWarehouse.schema.fact1
SELECT *
FROM Database.schema.table1
My datawarehouse is always in localhost But "Database.schema.table1" could be in different servers therefore I will have Different linkservers in our customer's servers to retrieve its data.
This means for example I will need the query change like this for customer1 :
INSERT DataWarehouse.schema.fact1
SELECT *
FROM [192.168.1.100].Database.schema.table1
And for customer2 I will need the query to be like this :
INSERT DataWarehouse.schema.fact1
SELECT *
FROM [10.2.5.100].Database.schema.table1
I've tried extract and loading with SSIS components but because of my complex queries, It became so messy.
Any ideas how to make my query dynamic?
As per this link Changing Properties of a Linked Server in SQL Server
One way to solve your problem is to make sure that the linked server logical name is always the same, regardless of what the actual physical host is.
So the process here would be:
Create the linked server with the linked server wizard
Use this to rename the server to a consistent name that can be used in your code
i.e.
EXEC master.dbo.sp_serveroption
#server=N'192.168.1.100',
#optname=N'name',
#optvalue=N'ALinkedServer'
Now you can refer to ALinkedServer in your code
A better way is to script the linked server creation properly - don't use the SSMS wizard
Here's the template - you need to do more research to fund out the correct values here
USE master;
GO
EXEC sp_addlinkedserver
#server = 'ConsistentServerName',
#srvproduct = 'product name',
#provider = 'provider name',
#datasrc = 'ActualPhysicalServerName',
#location = 'location',
#provstr = 'provider string',
#catalog = 'catalog';
GO
But the last word is: Don't use linked servers. Use SSIS
I would suggest you to do the below steps to execute same statement across multiple servers. As suggested by #Nick.McDermaid, I would strongly recommend against linked server. It is better to go for exact server name in SSIS.
Put the INSERT statement into a separate variable
Create a foreach container in SSIS.
Inside foreach containter, have a script task and get the current server name from the list of servernames. You can have comma separated list of servernames and get current one.
Again, inside foreach container, create Execute Process Task & call Sqlcmd.exe with connection information specific to each server, based on the server name got in Step No. 3, using SSIS expressions. Refer to this Stackoverflow post on using expressions for Execute ProcessTask for more information on calling Execute process task in SSIS.
How about making a SSIS package that works for one of your systems.
Parameterize your working package to accept a connection string
create another package that loops thru your connection strings and calls your working package and passes the conn string

How can I query over all db of my server without looping over DB in pymssql connection

I'd like first to know how to make a query over all the databases in my server instance with pymssql (in MSSQL management studio = right click --> new query on the server thumbnail then don't need to specify the name of the db in the query - it just gives you one more column in the output which is the segment from which the record is from). Then how do you do the same as registered servers on two or multiple hosts (I have 2 hosts and I want to pass the same query do I really need to make the two connections ?)
thanks
You could use sp_foreachdb, like this:
EXECUTE master.sys.sp_MSforeachdb 'USE [?]; EXEC update table set foo = bar'
Maybe this can help you (but - to be honest - I did not really understand what you want :-) )
SELECT * FROM sys.databases

SQL Server Linked Server Example Query

While in Management Studio, I am trying to run a query/do a join between two linked servers.
Is this a correct syntax using linked db servers:
select foo.id
from databaseserver1.db1.table1 foo,
databaseserver2.db1.table1 bar
where foo.name=bar.name
Basically, do you just preface the db server name to the db.table ?
The format should probably be:
<server>.<database>.<schema>.<table>
For example:
DatabaseServer1.db1.dbo.table1
Update: I know this is an old question and the answer I have is correct; however, I think any one else stumbling upon this should know a few things.
Namely, when querying against a linked server in a join situation the ENTIRE table from the linked server will likely be downloaded to the server the query is executing from in order to do the join operation. In the OP's case, both table1 from DB1 and table1 from DB2 will be transferred in their entirety to the server executing the query, presumably named DB3.
If you have large tables, this may result in an operation that takes a long time to execute. After all it is now constrained by network traffic speeds which is orders of magnitude slower than memory or even disk transfer speeds.
If possible, perform a single query against the remote server, without joining to a local table, to pull the data you need into a temp table. Then query off of that.
If that's not possible then you need to look at the various things that would cause SQL server to have to load the entire table locally. For example using GETDATE() or even certain joins. Others performance killers include not giving appropriate rights.
See http://thomaslarock.com/2013/05/top-3-performance-killers-for-linked-server-queries/ for some more info.
SELECT * FROM OPENQUERY([SERVER_NAME], 'SELECT * FROM DATABASE_NAME..TABLENAME')
This may help you.
For those having trouble with these other answers , try OPENQUERY
Example:
SELECT * FROM OPENQUERY([LinkedServer], 'select * from [DBName].[schema].[tablename]')
If you still find issue with <server>.<database>.<schema>.<table>
Enclose server name in []
You need to specify the schema/owner (dbo by default) as part of the reference. Also, it would be preferable to use the newer (ANSI-92) join style.
select foo.id
from databaseserver1.db1.dbo.table1 foo
inner join databaseserver2.db1.dbo.table1 bar
on foo.name = bar.name
select * from [Server].[database].[schema].[tablename]
This is the correct way to call.
Be sure to verify that the servers are linked before executing the query!
To check for linked servers call:
EXEC sys.sp_linkedservers
right click on a table and click script table as select
select name from drsql01.test.dbo.employee
drslq01 is servernmae --linked serer
test is database name
dbo is schema -default schema
employee is table name
I hope it helps to understand, how to execute query for linked server
Usually direct queries should not be used in case of linked server because it heavily use temp database of SQL server. At first step data is retrieved into temp DB then filtering occur. There are many threads about this. It is better to use open OPENQUERY because it passes SQL to the source linked server and then it return filtered results e.g.
SELECT *
FROM OPENQUERY(Linked_Server_Name , 'select * from TableName where ID = 500')
For what it's worth, I found the following syntax to work the best:
SELECT * FROM [LINKED_SERVER]...[TABLE]
I couldn't get the recommendations of others to work, using the database name. Additionally, this data source has no schema.
In sql-server(local) there are two ways to query data from a linked server(remote).
Distributed query (four part notation):
Might not work with all remote servers. If your remote server is MySQL then distributed query will not work.
Filters and joins might not work efficiently. If you have a simple query with WHERE clause, sql-server(local) might first fetch entire table from the remote server and then apply the WHERE clause locally. In case of large tables this is very inefficient since a lot of data will be moved from remote to local. However this is not always the case. If the local server has access to remote server's table statistics then it might be as efficient as using openquery More details
On the positive side T-SQL syntax will work.
SELECT * FROM [SERVER_NAME].[DATABASE_NAME].[SCHEMA_NAME].[TABLE_NAME]
OPENQUERY
This is basically a pass-through. The query is fully processed on the remote server thus will make use of index or any optimization on the remote server. Effectively reducing the amount of data transferred from the remote to local sql-server.
Minor drawback of this approach is that T-SQL syntax will not work if the remote server is anything other than sql-server.
SELECT * FROM OPENQUERY([SERVER_NAME], 'SELECT * FROM DATABASE_NAME.SCHEMA_NAME.TABLENAME')
Overall OPENQUERY seems like a much better option to use in majority of the cases.
I have done to find out the data type in the table at link_server using openquery and the results were successful.
SELECT * FROM OPENQUERY (LINKSERVERNAME, '
SELECT DATA_TYPE, COLUMN_NAME
FROM [DATABASENAME].INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME =''TABLENAME''
')
Its work for me
Following Query is work best.
Try this Query:
SELECT * FROM OPENQUERY([LINKED_SERVER_NAME], 'SELECT * FROM [DATABASE_NAME].[SCHEMA].[TABLE_NAME]')
It Very helps to link MySQL to MS SQL
PostgreSQL:
You must provide a database name in the Data Source DSN.
Run Management Studio as Administrator
You must omit the DBName from the query:
SELECT * FROM OPENQUERY([LinkedServer], 'select * from schema."tablename"')
For MariaDB (and so probably MySQL), attempting to specify the schema using the three-dot syntax did not work, resulting in the error "invalid use of schema or catalog". The following solution worked:
In SSMS, go to Server Objects > Linked Servers > Providers > MSDASQL
Ensure that "Dynamic parameter", "Level zero only", and "Allow inprocess" are all checked
You can then query any schema and table using the following syntax:
SELECT TOP 10 *
FROM LinkedServerName...[SchemaName.TableName]
Source: SELECT * FROM MySQL Linked Server using SQL Server without OpenQuery
Have you tried adding " around the first name?
like:
select foo.id
from "databaseserver1".db1.table1 foo,
"databaseserver2".db1.table1 bar
where foo.name=bar.name

Version Agnostic SQL Server Script/Statement that detects existence of a specific database

Due to the packaged nature of the release, a SQL Server script (well more of a statement) needs to be created that can execute correctly on SQL Server 7.0 thru 2008 which can essentially achieve this:
if exists(select * from sys.databases where name = 'Blah')
Reasons this is difficult:
SQL 7 'sys.databases' is not valid
SQL 2008 'sysdatabases' is not valid
I stupidly parsed out the version number using serverproperty, to allow an IF depending on the version:
if (select CONVERT(int,replace(CONVERT(char(3),serverproperty ('productversion')),'.',''))) >= 80
Then discovered serverproperty does not exist under SQL 7.
Note that the SQL can be remote from the install, so no futzing around on the local machine - reg entries/file versions etc is of any use.
SQL Server error handling (especially 7.0) is poor, or maybe I don't understand it well enough to make it do a kind of try/catch.
I am now getting problem blindness to this, so any pointers would be appreciated.
Thanks,
Gareth
Try
USE database
and test ##ERROR.
USE database
IF ##ERROR <> 0 GOTO ErrExit
logic ...
RETURN 0
ErrExit:
RETURN 1
(or RAISERROR, or ...)
Thanks G Mastros
This looks like it might yield a 100% solution. It is available under SQL 7.
I need to complete and test, but at first glance I think it will fly.
Here's the draft code FYI.
create table #dwch_temp
(
name sysname
,db_size nvarchar(13)
,owner sysname
,dbid smallint
,created nvarchar(11)
,status nvarchar(600)
,compatibility_level tinyint
)
go
insert into #dwch_temp
exec sp_helpdb
if exists(select name from #dwch_temp where name = 'DWCHServer')
-- run the code
drop table #dwch_temp
You could try a TRY... CATCH around a USE [DatabaseName].
I don't have access to a SQL 7 instance, but I encourage you to try:
sp_helpDB
I know this works on sql 2000 and sql 2005 to get a list of databases. I suspect it works on SQL 7, too.
sysdatabases is a remnant from the Sybase era and is still present in SQL 2008 (although deprecated). You can check for the existence of a database with a query like this:
IF EXISTS (SELECT 1 FROM master..sysdatabases where name = 'Blah')

Resources