PHP / MySQLi - Select from 2 databases [duplicate] - php

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

Related

php pdo fetchAll returns SQL error 'no active fields' when executing stored procedure

My stored procedure executes 100% fine from the Management Studio, but when running through PDO with a try catch block I get the following exception message:
SQLSTATE[IMSSP]: The active result for the query contains no fields.
I have tried the classic SET NOCOUNT ON (this caught me out previously) to stop it returning row counts, and I've done various tests by removing sections of the SP until I have found which section the error lies in. I've also tried the PHP PDO nextRowset() with no luck.
The Stored Procedure:
I declare a cursor (shock, horror I know!) and iterate over some results, which itself caused no issues - but in reality this cursor must run various stored procedures itself for each fetch in the cursor, and when I introduce these stored procedures that is when the issues appear.
I have gone through the SPs inside the cursor and SET NOCOUNT ON on them in case that might be the issue, but no luck. One or two of these SPs have OUTPUTS but these are captured in variables accordingly.
Does anyone have any ideas? I don't wish to post any code of the project but some scenarios of commands I perform in the cursor block:
SELECT #varName = columnName FROM dbo.tableName
SET #varName = (SELECT columnName FROM dbo.tableName)
EXEC dbo.storedProcedure #outputVar OUTPUT
My best guess is the top example is the problem, but I am not knowledgeable to know. I would like to locate the error without removing these one by one as the actions performed by the procedure as a whole are difficult to roll-back on my test database and each line is important to getting correct output.
Thanks in advance for any help provided!
I have now managed to solve this! Hopefully the solution will help others who run into this error or similar.
The issue was that nested cursors (cursor inside cursor) were in use for the SQL Server stored procedure. My main procedure (called from PHP by PDO) opened a cursor and then ran other stored procedures inside that cursor that opened a cursor of their own.
This method works fine when running the query in SQL Server Management Studio, but calling from PHP via PDO fails.
While I know that using cursors is considered bad practice by most SQL buffs, unfortunately I inherited these stored procedures so I'm removing all blame from myself!
The actual solution was to replace the cursor in the originating stored procedure (the one called by PHP which in turn calls the other SPs) with a while loop using code like this:
DECLARE #loopTable table (id int IDENTITY(1,1), dataColumn)
DECLARE #id int
DECLARE #rows int
DECLARE #data int -- var to hold targeted data in the loop
INSERT INTO #loopTable (dataColumn)
SELECT dataColumn FROM dataTable
SELECT #rows = COUNT(1) FROM #loopTable
WHILE (#rows > 0)
BEGIN
SELECT TOP 1 #data = dataColumn, #id = id FROM #loopTable
// Do stuff with #data variable here
DELETE FROM #loopTable where id = #id
SELECT #rows = COUNT(1) from #loopTable
END
Problem solved, nightmare to find!

how to use sql connection in PHP to execute a query on two databases

how can i run a query that joins two tables from TWO different Databases in mssql_query or mysql_query in php
for example
$conn=mssql_connect($ip,$username,$password);
mssql_select_db("DB1",$conn);
$q="select A.name,B.ID from DB1.dbo.T1 A, DB2.dbo.T2 B where A.ID=B.ID";
$res=mssql_query($q);
how to run such query??
Just prefix the tablenames with the database name, as you are already doing.
The user login that you are using to connect to mySQL needs to have access to both databases. Without this, it is impossible.
I think something like this:
SELECT X.field1, Y.field2
FROM database1.table_a AS X
INNER JOIN database2.table_b as Y
ON X.id=Y.id
[EDITED]
Sorry I didn't finish the post, you should use mysqli http://www.php.net/manual/en/mysqli.query.php (don't worry for the constructor, put just 1 database) and run the query as a regular query. Also, like the guy in the top said, the user that makes the query must have the permissions for both tables.

pdo mysql select statement working on one table while it is not working on other

I am having a strange problem.
I am using PDO prepared statement.
I have two tables with the name of TABLE1 AND TABLE2.
TABLE1 is copied from another db with its data.
TABLE2 is created using phpmyAdmin,
Both Tables are in the same Database.
I am running a Select statement using PDO prepare and its working fine on TABLE1 (which is copied from another DB) while it is not working on TABLE2 (which is created using phpmyadmin). No error and No exception. Strange?
does PDO prepare statement requires any specific type of table? or another setting which i don't know?
I find the solution myself. actually pdo requires fully qualified name to access table which was created using phpmyadmin.
so run the select statement using Following queries.
SELECT * FROM DB1.TABLE2 (successfully return the result set)
While I can access my Copied table (TABLE1) from another database without using DB1.
SELECT * FROM TABLE1 (successfully return the result set)
Cheers!

How do I construct a cross database query in PHP?

In our last episode (How I constructed a cross database query in MySQL) I learned how to construct a cross database query in MySQL. This worked great but when our hero tried to use this newfound knowledge in PHP he found his best friend FAIL waiting for him.
I took a look at mysql_select_db for PHP. This seems to imply that if I want to use MySQL with PHP, I have a couple of choices:
Use mysql_select_db but be stuck with only using one db at a time. This is our current setup and putting a database as a namespace identifier doesn't seem to work (it works fine in the MySQL shell so I know it's not a problem with our MySQL server setup).
Don't use mysql_select_db. From some of the examples I've seen, this seems to mean that I have to specify the db for every query that I make. This makes sense since I haven't used mysql_select_db to tell PHP what db I want to access. This also makes sad since I don't want to go through all my code and prepend a db name to every query.
Is there something better than this? Is there a way for me to do a cross db MySQL query in PHP without having to something crazy like (2)?
CLARIFICATION: None of the proposed answers actually let me do a cross db query. Instead, they allow me to access two different DBs separately. I want a solution that allows me to do something like SELECT foreign_db.login.username, firstname, lastname from foreign_db.login, user where ... NOT just make different queries to different DBs. For what it's worth, (2) doesn't work for me.
You will need your databases to run on the same host.
If so, you should be able to use mysql_select_db on your favourite/default db and manually specify a foreign database.
$db = mysql_connect($hots, $user, $password);
mysql_select_db('my_most_used_db', $db);
$q = mysql_query("
SELECT *
FROM table_on_default_db a, `another_db`.`table_on_another_db` b
WHERE a.id = b.fk_id
");
If your databases run on a different host, you won't be able to join directly. But you can then make 2 queries.
$db1 = mysql_connect($host1, $user1, $password1);
$db2 = mysql_connect($host2, $user2, $password2);
$q1 = mysql_query("
SELECT id
FROM table
WHERE [..your criteria for db1 here..]
", $db1);
$tmp = array();
while($val = mysql_fetch_array($q1))
$tmp[] = $val['id'];
$q2 = mysql_query("
SELECT *
FROM table2
WHERE fk_id in (".implode(', ', $tmp).")
", $db2);
After reading your clarification, I am under the impression that you actually want to query tables residing in two separate MySQL server instances. At least, your clarification text:
SELECT foreign_db.login.username, firstname, lastname from foreign_db.login, user where
suggests that you want to run one query while being logged in as two users (which may or may not reside on the same mysql server instance).
In your question, you said you wanted to query data from two different databases, but it is important to realize that one MySQL instance can have many, many databases. For multiple databases managed by the same mysql instance, the solution proposed in the question you linked to simply works: just prefix the table name with the name of the databases, separating database and table names with a dot: <db-name>.<table-name>.
But, like i pointed out, this only works if:
all databases you access in one query reside on the same server - that is, are managed by the same MySQL instance
the user that is connected to the database has the right privileges to access both tables.
Scenario1: databases on same host: grant appopriate privileges and qualify table names
So if the tables actually reside on the same mysql instance, there is no need for a second login or connection - simply grant the database user you use to connect to the datbase the appropriate privileges to select from all tables you need. You can do that with the GRANT syntax, documented here: http://dev.mysql.com/doc/refman/5.1/en/grant.html
For example, GRANT SELECT ON sakila.film TO 'test'#'%' will allow the user test#% to select data from the film table in the sakila database. After doing that, said user can refer to this table using sakila.film (so-called qualified table name), or if the current database is set to sakila, simply as film
Scenario2: databases managed by different MySQL instances: FEDERATED engine
If the tables you want to access are actually managed by two different MySQL instances, there is one trick that may or may not work, depending on your configuration. Since MySQL 5.0 mysql supports the FEDERATED storage engine. This lets you create a table that is not actually a table, but a peephole to a table on a remote server. This engine is documented here: http://dev.mysql.com/doc/refman/5.1/en/federated-storage-engine.html
For example, if you know there is this table in the misc database on the remote host:
CREATE TABLE t (
id int not null primary key
, name varchar(10) not null unique
)
you can make a local 'pointer' to that remote table using this:
CREATE TABLE t (
id int not null primary key
, name varchar(10) not null unique
)
ENGINE = FEDERATED
CONNECTION='mysql://<user>#<remote-server>:<remote-port>/misc/t';
Unfortunately, the FEDERATED engine is not always available, so you have to check first if you can even use that. But suppose it is, then you can simply use the local table t in your queries, just like any other table, and MySQL will communicate with the remote server and perform the appropriate operations on the physical table on the other side.
Caveat: there are several optimization issues with FEDERATED tables. You should find out if and to what extent these apply to you. For instance, applying a WHERE to a federated table can in many cases result in the entire table contents being pullled over the wire to your local server, where the actual filtering will be appplied. Another issue is with table creation: you have to be very sure that the definitions of the federated table and the table it is pointing to match exacty, except for the ENGINE clause (and CONNECTION). If you have for example a different character set, the data may arrive completely garbled after travelling over the wire.
If you want to use FEDERATED tables, do read this article http://oreilly.com/pub/a/databases/2006/08/10/mysql-federated-tables.html to decide if its right for your particular use case.
If you think you do need it, I have a utility to create federated tables here: http://forge.mysql.com/tools/tool.php?id=54
Scenario3: can't use FEDERATED, but tables on different MySQL instances
Finally, if you have tables on different MySQL instances, but cannot for some reason use the federated table engine, your a out of luck I'm afraid. You are simply going to have to execute queries to both MySQL instances, receive the results and do something intelligent with it in PHP. depending on your exact requirements, this may be a perfectly viable solution
I guess you need to decide for yourself which part of my answer best appeals to your problem, and add a comment in case you need more help. TIA Roland.
A solution might be to :
use mysql_select_db to select the "default" (i.e. most used) database
and specify the DB name only in queries that have to work with the "second" (i.e. least used) database.
But this is only a viable solution if you have one DB that's more used than the other...
Out of curiosity : did you try establishing several connections to your DB server -- i.e. one for each database ?
You might be able to :
connect to the first DB with mysql_connect, and, then, select the first DB with mysql_select_db
and, then, connect to the second DB, passing true for the new_link parameter of mysql_connect if necessary, and, then, selecting the second DB with mysql_select_db
Then, work with the connection identifier returned by the first, or second, call to mysql_connect, depending on which DB you want to issue queries.
As a sidenote : the "best" / "cleanest" solution would be not using mysql_* functions directly, but working with some kind of ORM framework, that would have the ability to work with several DB connections at the same time (not sure, but maybe Doctrine can do that -- it's a real good ORM)
I set up tables in separate test databases as follows:
mysql> use test;
mysql> create table foo as select 42 as id from dual;
mysql> create database test2;
mysql> use test2;
mysql> create table bar as select 42 as id from dual;
I ran the following PHP script with MySQL 5.1.41 and PHP 5.3.1 on Mac OS X:
<?php
$link = mysql_connect('localhost', 'root', 'XXXX')
or die('There was a problem connecting to the database.');
mysql_select_db('test');
$sql = "SELECT * FROM foo JOIN test2.bar USING (id)";
if (($result = mysql_query($sql)) === FALSE) {
die(mysql_error());
}
while ($row = mysql_fetch_array($result)) {
print_r($row);
}
This test succeeds. The result is the join between the two tables in separate databases.
You should always be able to select from table(s) qualified by their respective database names in SQL. The mysql API in PHP does not restrict you to querying one database.
You should always be able to omit the database qualifier for the "current" database, which you declare with mysql_select_db().
Maybe this is the code that you want
//create links
$link1 = mysql_connect('localhost', 'mysql_user', 'mysql_password');
$link2 = mysql_connect('localhost', 'mysql_user', 'mysql_password');
//set db on every link
mysql_select_db('foo', $link1);
mysql_select_db('bar', $link2);
//do query with specified link
$result1 = mysql_query($query1,$link1);
$result2 = mysql_query($query2,$link2);
Note that we didn't do a mysql_select_db between queries , and we didn't use the database name in the query either.
Whenever you are SELECTing from multiple tables you have to sepcify an alias. So it's pretty simple from there:
SELECT
a.id, a.name, a.phone,
b.service, b.provider
FROM
`people` AS a,
LEFT JOIN
`other_database`.`providers` AS b ON a.id = b.userid
WHERE
a.username = 'sirlancelot'
As others on this page have mentioned, the database must be on the same host and instance. You cannot query a database from another server with this syntax.
The less verbose option you have is provided by the MySQL Manual itself:
The following example accesses the
author table from the db1 database and
the editor table from the db2
database:
USE db1;
SELECT author_name, editor_name FROM author, db2.editor
WHERE author.editor_id = db2.editor.editor_id;
You can use option two: "Don't use mysql_select_db" and then use mysql_db_query instead of mysql_query ... which is a simple find and replace.
Best of luck!
I've just tried this simple code in my computer and it works perfectly:
<?php
$conn = mysql_connect('localhost', 'root', '....');
mysql_select_db('aliro');
$sql = 'select * ' .
'from aliro_permissions a ' .
'left join cmsmadesimple.cms_permissions b on a.id=b.permission_id ';
$res = mysql_query($sql)
or die(mysql_error());
while($row = mysql_fetch_assoc($res)){
print_r($row);
}
?>
(Of course, the query itself is meaningless, it's just an example.)
So I can't really see what your exact problem is. If you want a syntax that's simpler that this, you'll have to provide an example of what kind of SQL you want to write.

PHP Get the last insert id from ODBC connection

How do I get the last insert id from a database using a ODBC connection?
I'm looking for a solution similar to the mysql_insert_id() function.
SELECT ##IDENTITY AS ID
If you're using databases with PHP I strongly recommend using PDO (simple database wrapper for a lot of common database engines, more and more supported all the time, part of PHP canon), and hence use PDO::lastInsertId if your database supports the equivalent of mysql_insert_id.
Don't use "SELECT max(id) FROM table;" as it can result in seriously freaky and hard-to-find bugs later on.
* **UPDATE : Ok, you're using ODBC, and I suspect you're after odbc_cursor. I still stand by the strong recomendation to use PDO, as it has an ODBC driver. (ODBC in my eyes is an grumpy bitter old man who mumbles under his breath driving his truck that's falling apart, as the hip and effective PDO guys race past in their sexy VOLVO S90's)
It depends on the database type, but look into the SEQUENCE syntax for your rdbm.
I used "SELECT ##IDENTITY AS LastID", while working with PHP/MSSQL, through ODBC. That brought some issues under SQL 2005 server (or was it 2000?).
Either way if you do like this:
SET NOCOUNT ON
[NOW INSERT YOUR INSERT SQL QUERY]
SELECT ##IDENTITY AS LastID
you should be just fine in any MSSQL server version.
"SET NOCOUNT ON" will prevent sql server from sending messages like '1 rows inserted', which will keep your script working properly.
If you have MySQL under ODBC - you can use the next query:
"SELECT LAST_INSERT_ID( );"
It have to be executed mmediately after executing INSERT-query.
For other database - use other specific queries...
Use in MySQL
SELECT *
FROM table_name
ORDER BY Id Desc
LIMIT 1
Use in SQL Server
SELECT top 1 *
FROM table_name
ORDER BY Id Desc
Are you inserting rows into your database via PHP? If so, perhaps you can generate a unique primary key using uniqid() - then you will know the ID without having to query the database.
If it is not possible to update the key type, perhaps you can still insert a unique id when you do the inserts, so you could do a query like this:
SELECT id FROM mytable WHERE rowid = '$myuniqueid'
That way you're ensuring that you're pulling back the correct ID from the database - a much better solution than MAX(id).
Using
SELECT max(id) FROM table;
should be fine from inside a transaction, or does ODBC not support transactions?

Categories