Problem to data access from sql db by using r studio - sql

I can able to connect DB by using following code
library(RODBC)
library(DBI)
library(odbc)
conn3 <- DBI::dbConnect(odbc :: odbc(),
Driver = 'SQL Server',
Server = 'xxx',
Database = 'xxx',
UID = 'xxx',
Pwd = 'xxx',
TrustServerCertificate='no',
#trusted_connection = 'yes',
Port = 1433
)
And i can able to see the DB data table.
But when i try to access the data by using following code
myquery <- dbSendQuery(conn3, "SELECT * FROM mhealthpbi1.report.blood_test")
df<-dbFetch(myquery)
It showws the following error
Error in result_fetch(res#ptr, n) :
nanodbc/nanodbc.cpp:3069: 07009: [Microsoft][ODBC SQL Server Driver]Invalid Descriptor Index
and show the error message (image attached)
can anyone help me to access or extract data?
can anyone help me to access or extract data by providing code or explain process?

Try myquery <- dbSendQuery(conn3, "SELECT * FROM mhealthpbi1.report.blood_test;") or make sure the table name is correct, remember that you have already selected the database in dbConnect.
Example for mySQL:
mysqlconnection = dbConnect(RMySQL::MySQL(),
dbname='cars',
host='localhost',
port=3306,
user='xxx',
password='xxx')
brand = fetch(dbSendQuery(mysqlconnection, "select brand from sale_2018"))

In my experience, this error can be caused by a MS ODBC-driver (ahem) "feature": all long columns (ill-bounded constraint) must be at the end of the list of columns1. I'm inferring that you have an odbc version older than 1.3.1, since it was sufficiently mitigated in that release.
Two options:
See if/which columns are "large", often created as nvarchar(max) or blob:
fields <-
DBI::dbGetQuery(conn3,
"select TABLE_NAME, COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH
from information_schema.columns
where TABLE_NAME='blood_test'")
Look at fields, and if character_maximum_length is over -1 (max) or possibly a high number over 255 or so, then that column should be at the end. In this case, you'll need to change from select * to specific columns. (Many SQL gurus discourage select * anyway, for reasons relating to defensive programming and unsupervised/automated queries.)
If you really "need" select *, then I suggest you write a sql VIEW that orders the columns correctly, and then allows one to select *. Crafting this is rather simple assuming that the user permissions in the database allows it. If so, then it may be as simple as
CREATE VIEW myview AS
select column1, column3, column5,
bigcolumn2, bigcolumn4
from mhealthpbi1.report.blood_test
and then subsequently use select * from myview.
Update your version of odbc-1.3.1 or newer (1.3.3 is current as of this writing), as it should resolve the issue.
Notes:
https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/getting-long-data

Related

Get full "path" of SQL tables with R DBI package

I'm new to SQL so I don't know the correct wordings, sorry for that.
When I establish a connection with dbConnect of the DBI package, I can list all tables of the database:
> head(dbListTables(conn))
[1] "cdw_apps" "cdw_attachments"
[3] "cdw_auditLogs" "cdw_blueprints"
[5] "cdw_businessObjects" "cdw_businessObjectsActions"
However I can't access directly to these tables, they are nested (in some kind of "folders", I don't know the wording, again).
For example I have to do:
dbGetQuery(
conn,
"select top 100 * from [vxda-prod-sqldw01].[vxrd_cdw].[cdw_apps]"
)
Is it possible to list the tables with their "path" (I mean [vxda-prod-sqldw01].[vxrd_cdw].[cdw_apps] and not only cdw_apps)?
Most databases support information_schema.tables (and .columns, .routines, and others I believe), and SQL Server is among them. While there are newer object-discovery tables/mechanisms specifically in T-SQL, these still work and are sufficient for this need.
For instance,
DBI::dbGetQuery(conn, "select * from information_schema.tables")
# TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE
# 1 mycatalog dbo table1 BASE TABLE
# 2 mycatalog dbo table2 BASE TABLE
# 3 mycatalog dbo someview VIEW
will return all tables (and views) visible.

R and MSSQL - communication with temp tables (table not found on channel)

I'm trying to update global temp table using RODBC in a following way:
library(RODBC)
channel <- odbcConnect("RDataSource", uid = "user", pwd = "password")
query <- "select * from ##TempTable"
table_data <- sqlQuery(channel, query)
# data frame creation
sqlUpdate(channel, data_frame, index = "id", verbose = TRUE, tablename = "##TempTable")
Select query executes well, but sqlUpdate is failed with error message:
"Error in odbcTableExists(channel, tablename) : ‘##TempTable’: table not found on channel"
I suppose that the reason of this error may be connected with using of '#' in the name of temp tables.
UPD: I'm getting the same error with sqlSave function. This error occures only when I'm creating temp table, everything is ok with usual SQL tables.
Global temp table is creating before the calling of R code.
So, is there any way to communicate with temp tables in MSSQL database using R functions such as sqlSave() and sqlUpdate()?
I finally found that the cause of this error was in the settings of ODBC Data Source. It seems that communication with temp tables using R functions such as sqlSave or sqlUpdate requires the default database in ODBC data source to be set to 'tempdb'.
So, now I'm able to use sqlSave() function to insert values in temp table. This function in fact has much better performance than using sqlQuery function with the direct 'INSERT' query as a parameter.

How to get data from two databases in two servers with one SELECT statement?

I don't actually want to modify either database, just get the data.
I know how to connect to each database individually, with these connection strings:
Provider=SQLOLEDB.1;Data Source={0};Initial Catalog={1};Integrated Security=SSPI;Persist Security Info=False;
Provider=OraOLEDB.Oracle.1;Data Source={0};User ID={1};Password={2};Persist Security Info=True;
But how can I get this overlapping data together? Is that even possible, especially considering that one is Oracle and one is SQL Server? Or would it be better to do the SELECT statements on each database individually and then match them after?
For example, how would I get all students that are 10 years old and like the color blue?
Notice that all items in DatabaseB have an ID that maps to DatabaseA, but not the other way around.
I have done this with MySQL,Oracle and SQL server. You can create linked servers from a central MSSQL server to your Oracle and other MSSQL servers. You can then either query the object directly using the linked server or you can create a synonymn to the linked server tables in your database.
Steps around creating and using a linked server are:
On your "main" MSSQL server create two linked servers to the servers that contains the two databases or as you said database A and database B.
You can then query the tables on the linked servers directly using plain TSQL select statements.
To create a linked server to Oracle see this link: http://support.microsoft.com/kb/280106
A little more about synonyms. If you are going to be using these linked server tables in a LOT of queries it might be worth the effort to use synonymns to help maintain the code for you. A synonymn allows you to reference something under a different name.
So for example when selecting data from a linked server you would generally use the following syntax to get the data:
SELECT *
FROM Linkedserver.database.schema.table
If you created a synonym for Linkedserver.database.schema.table as DBTable1 the syntax would be:
SELECT *
FROM DBTable1
It saves a bit on typing plus if your linked server ever changed you would not need to go do changes all over your code. Like I said this can really be of benefit if you use linked servers in a lot of code.
On a more cautionary note you CAN do a join between two table on different servers. HOwever this is normally painfully slow. I have found that you can select the data from the different server into temp tables and joining the temp tables can generally speed things up. Your milage might vary but if you are going to join the tables on the different servers this technique can help.
Let me know if you need more details.
Which database are you using? Most of databases come with concept called dblinks. You have to create a dblink of database B in database A and then you can create a synonym (not a must but for ease) and use it as if it is table of database A.
Looks like a heterogeneous join (data on disparate servers/technologies etc).
As such, not straightforward. If you can make Namphibian's method work, go that way.
Otherwise, you need to gather the data from both tables to a common location (one or other of the servers 'in play', or a third server/technology solely for the purpose of co-locating the data). Then you can join the data happily. Many ETL Tools work this way, and this situation (almost) always involves redistribution of one or more of the tables to a common location before joining.
Oracle Data Integrator ETL tool does this, so does Talend Open Studio's tJoin component.
HTH
Try creating 3 Linq queries in Visual Studio. One for SQL Server, one for Oracle and one to combine the 2 database objects.
SELECT (things)
FROM databaseA.dbo.table t1
INNER JOIN databaseB.dbo.table t2 ON t1.Col1 = t2.Col2
WHERE t1.Col1 = 'something'
EDIT - This statement should meet the new requirements:
SELECT *
FROM databaseA.dbo.table t1
INNER JOIN databaseB.dbo.table t2 ON t1.ID = t2.ID
WHERE t1.Age = 10 AND t2.FavoriteColor = 'Blue'
If you want to select data from two different servers and database I would do a union and not a join as the data from one may be like apples and the other may be like oranges. You still would need to set up linked Servers and I believe you may link Oracle and SQL Server if after certain versions as shown but you could do something like this:
select ColA, ColB, ColC
from (ServerASQLServer).(DatabaseA).(schema).(table)
UNION
select ColA, ColB, ColC
from (ServerBOracleServer).(DatabaseB).(schema).(table)
If you perform inner joins your data must share data types to bind to or else they will be ommitted from the dataset returned. A union must just shared column data types but does not care on the logic. You are in essence saying: "Put these two sets of varying rows together based on their column logic matching."
But you were mentioning connection strings so I was curious if you would want to do it in a type of code method like .NET? I could provide an idea for that too possibly.
Assuming the databases are on the same server, you should be able to do something like this:
SELECT t.field1, t.field2
FROM database.schema.table t
JOIN database2.scheme.table2 t2
on t.id = t2.id
WHERE t2.field3 = ...
If the databases are on separate servers, look into using Linked Servers.
While I was having trouble join those two tables, I got away with doing exactly what I wanted by opening both remote databases at the same time. MySQL 5.6 (php 7.1) and the other MySQL 5.1 (php 5.6)
//Open a new connection to the MySQL server
$mysqli1 = new mysqli('server1','user1','password1','database1');
$mysqli2 = new mysqli('server2','user2','password2','database2');
//Output any connection error
if ($mysqli1->connect_error) {
die('Error : ('. $mysqli1->connect_errno .') '. $mysqli1->connect_error);
} else {
echo "DB1 open OK<br>";
}
if ($mysqli2->connect_error) {
die('Error : ('. $mysqli2->connect_errno .') '. $mysqli2->connect_error);
} else {
echo "DB2 open OK<br><br>";
}
If you get those two OKs on screen, then both databases are open and ready. Then you can proceed to do your querys.
On your specific question I will do something like first selecting from database A all the 10 year old kids then match them to the colors by the ID from database B. It should work, I havent tested this code on my server, but my sample below this code works. You can custom query by anything, color, age, whatever, even group them as you require to.
$results = $mysqli1->query("SELECT * FROM DatabaseTableA where age=10");
while($row = $results->fetch_array()) {
$theColorID = $row[0];
$theName = $row[1];
$theAge = $row[2];
echo "Kid Color ID : ".$theColorID." ".$theName." ".$theAge."<br>";
$doSelectColor = $mysqli2->query("SELECT * FROM DatabaseTableB where favorite_color=".$theColorID." ");
while($row = $doSelectColor->fetch_assoc()) {
echo "Kid Favorite Color : ".$row["favorite_color"]."<br>";
}
}
I have use this to switch back and forth for our programs without joining tables from remote servers and have no problem so far.
$results = $mysqli1->query("SELECT * FROM video where video_id_old is NULL");
while($row = $results->fetch_array()) {
$theID = $row[0];
echo "Original ID : ".$theID." <br>";
$doInsert = $mysqli2->query("INSERT INTO video (...) VALUES (...)");
$doGetVideoID = $mysqli2->query("SELECT video_id, time_stamp from video where user_id = '".$row[13]."' and time_stamp = ".$row[28]." ");
while($row = $doGetVideoID->fetch_assoc()) {
echo "New video_id : ".$row["video_id"]." user_id : ".$row["user_id"]." time_stamp : ".$row["time_stamp"]."<br>";
$sql = "UPDATE video SET video_id_old = video_id, video_id = ".$row["video_id"]." where user_id = '".$row["user_id"]."' and video_id = ".$theID.";";
$sql .= "UPDATE video_audio SET video_id = ".$row["video_id"]." where video_id = ".$theID.";";
// Execute multi query if you want
if (mysqli_multi_query($mysqli1, $sql)) {
// Query successful do whatever...
}
}
}
// close connection
$mysqli1->close();
$mysqli2->close();
I was trying to do some joins but since I got those two DBs open, then I can go back and forth doing querys by just changing the connection $mysqli1 or $mysqli2
It worked for me, I hope it helps... Cheers
As long as both databases are in the same server you can refer to tables with the database name :)
SELECT * FROM db1.table1
join
db2.tbable2
WHERE db1.table1.col1 = db2.table2.col1;

How to get table schema from Progress database via odbc

I have a linked server set up between sql 2008 and a Progress OpenEdge 10.1b server.
How do I get the table schemas?
You can get all available tables:
select * from sysprogress.SYSTABLES;
or
select * from sysprogress.SYSTABLES_FULL;
You can get all columns of specified table:
select * from sysprogress.SYSCOLUMNS where TBL = 'table_name';
or
select * from sysprogress.SYSCOLUMNS_FULL where TBL = 'table_name';
It works only with DBA privileged user.
More detail in OpenEdge Product Documentation: https://community.progress.com/community_groups/openedge_general/w/openedgegeneral/1329.openedge-product-documentation-overview
Document title: SQL Reference
Chapter: OpenEdge SQL System Catalog Tables
You can do a statement like
SELECT * FROM LinkedProgressOpenedgeServer.YourDatabase.Owner.TableName WHERE 1=2
That should return just the schema without any data.
Normally the default schema name is PUB. You can try using PUB schema.

Select Query on 2 tables, on different database servers

I am trying to generate a report by querying 2 databases (Sybase) in classic ASP.
I have created 2 connection strings:
connA for databaseA
connB for databaseB
Both databases are present on the same server (don't know if this matters)
Queries:
q1 = SELECT column1 INTO #temp FROM databaseA..table1 WHERE xyz="A"
q2 = SELECT columnA,columnB,...,columnZ FROM table2 a #temp b WHERE b.column1=a.columnB
followed by:
response.Write(rstsql) <br>
set rstSQL = CreateObject("ADODB.Recordset")<br>
rstSQL.Open q1, connA<br>
rstSQL.Open q2, connB
When I try to open up this page in a browser, I get error message:
Microsoft OLE DB Provider for ODBC Drivers error '80040e37'
[DataDirect][ODBC Sybase Wire Protocol driver][SQL Server]#temp not found. Specify owner.objectname or use sp_help to check whether the object exists (sp_help may produce lots of output).
Could anyone please help me understand what the problem is and help me fix it?
Thanks.
With both queries, it looks like you are trying to insert into #temp. #temp is located on one of the databases (for arguments sake, databaseA). So when you try to insert into #temp from databaseB, it reports that it does not exist.
Try changing it from Into #temp From to Into databaseA.dbo.#temp From in both statements.
Also, make sure that the connection strings have permissions on the other DB, otherwise this will not work.
Update: relating to the temp table going out of scope - if you have one connection string that has permissions on both databases, then you could use this for both queries (while keeping the connection alive). While querying the table in the other DB, be sure to use [DBName].[Owner].[TableName] format when referring to the table.
your temp table is out of scope, it is only 'alive' during the first connection and will not be available in the 2nd connection
Just move all of it in one block of code and execute it inside one conection
temp is out of scope in q2.
All your work can be done in one query:
SELECT a.columnA, a.columnB,..., a.columnZ
FROM table2 a
INNER JOIN (SELECT databaseA..table1.column1
FROM databaseA..table1
WHERE databaseA..table1.xyz = 'A') b
ON a.columnB = b.column1