I am trying to create a temptable and do some calculations that populates the temptable and finally get the results from the created temp table. But so far I have been unsuccessful. My query is a little bit more involved but here is the thing that I am trying to do. This code assumes we have database connection set up with codeigniter.
-- This generate no results i.e. Array ()
$sql = "CREATE TABLE #output(name varchar NULL, id int NULL);
insert into #output (name,id) VALUES('sam',5)
SELECT * FROM #output";
$res = $this->db->query($sql);
--Also tried this and returns nothing
$queryList = [
'sql1' => "IF OBJECT_ID('tempdb.dbo.#output', 'U') IS NOT NULL DROP TABLE #output;",
'sql2' => "CREATE TABLE #output(name varchar NULL, id int NULL);",
'sql3' => "insert into #output (name,id) VALUES('sam',5)",
'sql4' => "SELECT * FROM #output"
];
$result = array();
foreach($queryList as $key => $value){
$result[$key] = $this->db->query($value, FALSE, TRUE);
}
These two were written to use codeigniter db drivers. None of the above queires even resulted in #output temptable in the tempdb of the database.
I also tried using sqlsrv_query directly, this one at least created the #output temptable but did not give me any results back.
-- Created the #output temptable but didn't give me back the data inserted
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( $conn ) {
echo "Connection established.<br />";
$sql = "CREATE TABLE #output(name varchar NULL, id int NULL);
insert into #output (name,id) VALUES('sam',5)
SELECT * FROM #output
--DROP TABLE #output";
$stm = sqlsrv_query($conn, $sql,[]);
while( $obj = sqlsrv_fetch_object( $stm )) {
echo $obj->name . '<br />';
//print_r($obj);
}
I have been trying a lot of scenarios but couldn't figure out what is wrong with my code. Oh BTW I also tried codeigniter trans_start() and end and added every query as a separate query but that didn't work out either. I couldn't think or search anything else and so here is my request for a help.
Here is my environment:
SQLSRV 5.3
SQL server 2012
ODBC Driver 17
CodeIgniter 3.1.9
PHP 7.0.31
Solution:
You need to fix some issues:
define varchar columns with this format: varchar [(n|max)]. When n is not specified, the default length is 1 and when you try to INSERT value 'sam', a warning will be generated.
put SET NOCOUNT ON; as first statement. If you miss that part, your statement will return more than one resultset, so you must make resultsets available by using sqlsrv_next_result().
Working example:
<?php
$server = 'server\instance,port';
$database = 'database';
$username = 'username';
$password = 'password';
$cinfo = array(
"Database" => $database,
"UID" => $username,
"PWD" => $password
);
$conn = sqlsrv_connect($server, $cinfo);
if ($conn === false) {
echo print_r(sqlsrv_errors(), true);
exit;
}
# Statement
$sql = "
SET NOCOUNT ON;
CREATE TABLE #output(name varchar(50) NULL, id int NULL);
INSERT INTO #output (name, id) VALUES ('sam', 5);
SELECT * FROM #output;
";
$stmt = sqlsrv_query($conn, $sql);
if ($stmt === false) {
echo print_r(sqlsrv_errors(), true);
exit;
}
# Results
while ($obj = sqlsrv_fetch_object($stmt)) {
echo 'Name: '.$obj->name.'</br>';
echo 'ID: '.$obj->id.'</br>';
}
# End
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
?>
Notes:
I'm not so familiar with CodeIgniter, but I think that this is your problem.
Related
I have a stored procedure that when called updates few tables and eventually returns an integer value.
When I call this stored procedure using SQL Pro tool, I get back a result as expected. The SQL that is auto-generated by the tool is this;
DECLARE #return_value int
EXEC #return_value =
dbo.GetNextReference
#c_tableName = 'prp',
#c_offYear = 'rcs14'
SELECT
'Return Value' = #return_value
However, I can't seem to get the same results or any results when I try to execute this using PHP PDO driver.
This is my code so far;
$conn = $this->getPDO();
$sql = "CALL GetNextReference (? , ?)";
$stmt = $conn->prepare($sql);
$tbl = 'prp';
$year = "rcs14";
$stmt->execute([$tbl, $year]);
$results = $stmt->fetchAll();
The statement executes without any errors but the results come back as an empty array.
What am I missing?
Sorry, I can't post the actual stored procedure as I am not permitted.
If I understand your question correctly and if you want to check the result of stored procedure execution, you may try with this:
<?php
# Connection
$server = 'server\instance,port';
$database = 'database';
$uid = 'user';
$pwd = 'password';
# Statement
try {
$conn = new PDO("sqlsrv:server=$server;Database=$database", $uid, $pwd);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch( PDOException $e ) {
die( "Error connecting to SQL Server" );
}
try {
$sql = "{? = call GetNextReference (? , ?)}";
# This should work also.
#$sql = "exec ? = GetNextReference (? , ?)";
$spresult = 0;
$tbl = 'prp';
$year = "rcs14";
$stmt = $conn->prepare($sql);
$stmt->bindParam(1, $spresult, PDO::PARAM_INT|PDO::PARAM_INPUT_OUTPUT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$stmt->bindParam(2, $tbl);
$stmt->bindParam(3, $year);
$stmt->execute();
# Next line for single resultset
#$results = $stmt->fetchAll();
# Multiple resultsets
do {
$results = $stmt->fetchAll();
print_r($results, true);
} while ($stmt->nextRowset());
} catch( PDOException $e ) {
die( "Error connecting to SQL Server" );
}
$stmt = null;
$conn = null;
echo 'Stored procedure return value : '.$spresult."</br>";
?>
Op has asked for an example of an OUTPUT parameter. it doesn't specifically answer their question, however, is far too long for a comment:
USE Sandbox;
GO
--Sample Table
CREATE TABLE dbo.TestTable (ID int IDENTITY(1,1),
SomeString varchar(20));
GO
--Sample proc
CREATE PROC dbo.TestSP #SomeString varchar(20), #ID int OUTPUT AS
--You cannot OUTPUT from an INSERT into a scalar variable, so we need a table variable
DECLARE #IDt table(ID int);
INSERT INTO dbo.TestTable (SomeString)
OUTPUT inserted.ID
INTO #IDt
SELECT #SomeString;
--Now set the scalar OUTPUT parameter to the value in the table variable
SET #ID = (SELECT ID FROM #IDt); --this works, as the SP is designed for only one row insertion
GO
DECLARE #SomeString varchar(20) = 'abc', #ID int;
EXEC dbo.TestSP #SomeString = #SomeString,
#ID = #ID OUTPUT; --ID now has the value of the IDENTITY column
--We can check here:
SELECT #ID AS OutputID;
SELECT *
FROM dbo.TestTable;
GO
--Clean up
DROP PROC dbo.TestSP;
DROP TABLE dbo.TestTable;
GO
This is not duplicated question, since I am asking how to use SET and INSERT in one PHP variable, there no any questions about AUTO_INCREMENT...
I have below page:
<?php
function genWO(){
$dbtype = "MySQL";
$username = "user";
$password = "pass";
$hostname = "10.10.10.10";
$dbname = "TABLES";
//connection to the database
$conn = new mysqli($hostname, $username, $password);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$insertNewWONum = "SET #MAX_WO = (SELECT max(WO_NUM) + 1 from GENERIC_TABLES.WO_NUMBERS); INSERT INTO GENERIC_TABLES.WO_NUMBERS (WO_NUM, WO_REQUESTOR) values (#MAX_WO, `test`)";
if ($conn->query($insertNewWONum) === TRUE) {
echo "New record created successfully". "<br>";
} else {
echo "Error: " . $insertNewWONum . "<br>" . $conn->error;
}
$getWONum = "SELECT LPAD(max(WO_NUM) ,6,0) as NEW_WO_NUM from GENERIC_TABLES.WO_NUMBERS";
$result = $conn->query($getWONum);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
echo "New WO Number: " . $row["NEW_WO_NUM"]. "<br>";
}
} else {
echo "0 results";
}
//close the connection
$conn->close();
}
?>
Since it is not allowed to use INSERT and SELECT for the same table in one query, I am trying to set variable and use it in INSERT query:
$insertNewWONum = "SET #MAX_WO = (SELECT max(WO_NUM) + 1 from GENERIC_TABLES.WO_NUMBERS); INSERT INTO GENERIC_TABLES.WO_NUMBERS (WO_NUM, WO_REQUESTOR) values (#MAX_WO, `test`)";
But it doesnt work, though it works fine if I am using this query in terminal.
Can anyone let me know how to achieve it please?
Since it is not allowed to use INSERT and SELECT for the same table in one query
All issues with your approach aside of course you can use INSERT and SELECT in one statement
INSERT INTO WO_NUMBERS (WO_NUM, WO_REQUESTOR)
SELECT COALESCE(MAX(WO_NUM), 0) + 1, 'Test'
FROM WO_NUMBERS;
Here is SQLFiddle demo.
Now what you need to realize is that your approach is unsafe for concurrent access. If this code is executed from two or more sessions simultaneously some or all of them may generate the same number effectively breaking your application.
Use AUTO_INCREMENT instead.
CREATE TABLE WO_NUMBERS
(
WO_NUM INT PRIMARY KEY AUTO_INCREMENT,
WO_REQUESTOR VARCHAR(32)
);
INSERT INTO WO_NUMBERS (WO_REQUESTOR) VALUES ('Test');
Here is SQLFiddle demo.
If for some reason you can't use AUTO_INCREMENT directly (and I honestly don't see why you couldn't) i.e. you need to add prefixes or augment the generated id/code in some way you can look this answer.
The following code works as expected (assuming the variables exist):
$connectionInfo = ['Database'=>$dbName, 'UID'=>$username, 'PWD'=>$pwd, 'ReturnDatesAsStrings'=>true, 'CharacterSet'=>'UTF-8'];
$conn = sqlsrv_connect($server, $connectionInfo);
$select = sqlsrv_query($conn, 'SELECT * INTO #mytable_temp FROM mytable WHERE myfield = \'myvalue\'', []);
$select2 = sqlsrv_query($conn, 'SELECT * FROM #mytable_temp ', []);
if (!$select2) {
$errors = sqlsrv_errors();
var_dump($errors);
} else {
$res = sqlsrv_fetch_array($select2, SQLSRV_FETCH_ASSOC);
var_dump($res);
}
However, if I change $select to the following, it doesn't work:
$select = sqlsrv_query($conn, 'SELECT * INTO #mytable_temp FROM mytable WHERE myfield = ?', ['myvalue']);
I get an error when running the second statement that says "Invalid object name '#mytable_temp". Why would using parameter binding cause the temp table to not be visible?
I am aware that I could get it working if I include both statements in the same sqlsrv_query() statement, but that's not an option for my use case. I also do know it works if using a global (##mytable_temp) table, but that's not an option either.
I'm running PHP 5.4.12 and tried the code on SQL Server 11.0.3 (2012 SP1) and 10.50.4000 (2008 SP2).
Here is my explanation of why the temp table is not seen after the SELECT INTO query that uses parameters.
Consider this T-SQL code (using MyTable created and populated as shown below):
DECLARE #stmt nvarchar(max) = 'SELECT * INTO #mytable_temp FROM mytable WHERE myfield = #P1';
EXECUTE sp_executesql #stmt, N'#P1 varchar(50)', #P1 = 'Value1';
If you run it in SSMS it runs fine and the output in the Messages window says:
(2 row(s) affected)
Try to add one line to the above code in the same SSMS window and run the whole batch:
DECLARE #stmt nvarchar(max) = 'SELECT * INTO #mytable_temp FROM mytable WHERE myfield = #P1';
EXECUTE sp_executesql #stmt, N'#P1 varchar(50)', #P1 = 'Value1';
SELECT * FROM #mytable_temp;
The output is:
(2 row(s) affected)
Msg 208, Level 16, State 0, Line 3
Invalid object name '#mytable_temp'.
The reason is that statement with parameters is executed by sp_executesql in the scope of the nested stored procedure and temporary tables created inside stored procedure are not visible to the caller of this stored procedure.
Execute sp_executeSql for select...into #table but Can't Select out Temp Table Data
https://msdn.microsoft.com/en-us/library/ms174979.aspx
A local temporary table created in a stored procedure is dropped
automatically when the stored procedure is finished. The table can be
referenced by any nested stored procedures executed by the stored
procedure that created the table. The table cannot be referenced by
the process that called the stored procedure that created the table.
When you prepare an SQL statement with parameters PHP eventually calls sp_executesql (most likely, though I didn't trace it). And you get this documented behavior - a temp table is created inside this stored procedure as part of the query and is immediately dropped when sp_executesql returns. When you run an SQL statement without parameters PHP sends it to the server as is without using sp_executesql.
There are few workarounds that come to mind.
Put several SQL statements into one long string and run it using one call to sqlsrv_query.
Make a stored procedure with parameters and put several SQL statements in it, then call your procedure with a single call to sqlsrv_query. (I personally prefer this approach).
Create (and optionally drop) temp table explicitly.
Here is the code that I used to verify that the last workaround works. Verified with PHP 5.4.28, SQL Server Express 2014, Microsoft driver for PHP SQLSRV 3.2. It creates temporary table explicitly using extra CREATE TABLE statement and then uses INSERT INTO instead of single SELECT INTO statement.
Create test table and populate with some data
CREATE TABLE [dbo].[MyTable](
[ID] [int] NOT NULL,
[MyField] [varchar](50) NOT NULL,
CONSTRAINT [PK_MyTable] PRIMARY KEY CLUSTERED
(
[ID] ASC
))
INSERT INTO [dbo].[MyTable] ([ID],[MyField]) VALUES
(1, 'Value1'),
(2, 'Value2'),
(3, 'Value3'),
(4, 'Value1')
Run php script
$connectionInfo = array("Database" => "tempdb");
$conn = sqlsrv_connect($serverName, $connectionInfo);
if ($conn)
{
echo "Connection established.\n";
}
else
{
echo "Connection could not be established.\n";
die( print_r( sqlsrv_errors(), true));
}
echo "Running CREATE TABLE ...\n";
$sql_create = "CREATE TABLE #mytable_temp([ID] [int] NOT NULL, [MyField] [varchar](50) NOT NULL)";
$stmt_create = sqlsrv_query($conn, $sql_create);
if( $stmt_create === false )
{
echo "CREATE TABLE failed\n";
die( print_r( sqlsrv_errors(), true));
}
else
{
echo "CREATE TABLE result set:\n";
while ($row = sqlsrv_fetch_array($stmt_create))
{
var_dump($row);
}
}
sqlsrv_free_stmt($stmt_create);
echo "Running INSERT INTO with param ...\n";
$select_into = "INSERT INTO #mytable_temp(ID, MyField) SELECT ID, MyField FROM MyTable WHERE MyField = ?";
$search = "Value1";
$params = array
(
array(&$search, SQLSRV_PARAM_IN)
);
$stmt_into = sqlsrv_query($conn, $select_into, $params);
if( $stmt_into === false )
{
echo "INSERT INTO failed\n";
die( print_r( sqlsrv_errors(), true));
}
else
{
echo "INSERT INTO result set:\n";
while ($row = sqlsrv_fetch_array($stmt_into))
{
var_dump($row);
}
}
sqlsrv_free_stmt($stmt_into);
echo "Running SELECT FROM ...\n";
$select_from = "SELECT * FROM #mytable_temp";
$stmt_from = sqlsrv_query($conn, $select_from);
if( $stmt_from === false )
{
echo "SELECT FROM failed\n";
die( print_r( sqlsrv_errors(), true));
}
else
{
echo "SELECT FROM result set:\n";
while ($row = sqlsrv_fetch_array($stmt_from))
{
var_dump($row);
}
}
echo "end\n";
Output of the script
Connection established.
Running CREATE TABLE ...
CREATE TABLE result set:
Running INSERT INTO with param ...
INSERT INTO result set:
Running SELECT FROM ...
SELECT FROM result set:
array(4) {
[0]=>
int(1)
["ID"]=>
int(1)
[1]=>
string(6) "Value1"
["MyField"]=>
string(6) "Value1"
}
array(4) {
[0]=>
int(4)
["ID"]=>
int(4)
[1]=>
string(6) "Value1"
["MyField"]=>
string(6) "Value1"
}
end
To complement Vladimir's answer, here are the trace results (PHP 5.6.9, MSSQL 2014 Express).
When you don't add any parameters
$select = sqlsrv_query($conn, 'SELECT * INTO #mytable_temp FROM mytable WHERE myfield = \'myvalue\'', []);
$select2 = sqlsrv_query($conn, 'SELECT * FROM #mytable_temp ', []);
PHP will send plain commands to MSSQL:
SELECT * INTO #mytable_temp FROM mytable WHERE myfield = 'myvalue'
SELECT * FROM #mytable_temp
When you add parameters
$select = sqlsrv_query($conn, 'SELECT * INTO #mytable_temp FROM mytable WHERE myfield = ?', ['myvalue']);
$select2 = sqlsrv_query($conn, 'SELECT * FROM #mytable_temp ', []);
PHP will then use sp_executesql:
exec sp_executesql N'SELECT * INTO #mytable_temp FROM mytable WHERE myfield = #P1',N'#P1 nvarchar(6)',N'myvalue'
SELECT * FROM #mytable_temp
I'm writing a upgrader for a mysql database using PHP. The behavior of the upgrader should be as follows.
If all the queries executed successfully the changes should be committed.
If a sinngle query get faild eveything should be roled back to previouse state.
Part of my program is as follows.
$host = 'localhost';
$user = 'root';
$password = 'root';
$db = 'transaction';
$con = mysqli_connect($host, $user, $password);
mysqli_select_db($con, $db);
mysqli_autocommit($con, FALSE);
$query1 = "create table `status` (
`id` int not null auto_increment,
`name` varchar(60) not null,
primary key (`id`)
) engine=innodb default charset=utf8;";
$result1 = mysqli_query($con, $query1);
$query2 = "ALTER TABLE status
CHANGE name value varchar(512);";
$result2 = mysqli_query($con, $query2);
if(!($result1 && $result2)) {
mysqli_rollback($con);
} else {
mysqli_commit($con);
}
mysqli_close($con);
But if the 'status' table already exists the first create table query is failing. So both queries should be rolled back. But the alter query has executed and not rolled back.
I saw a post which list all the queries which cannot be rolled back in mysql. http://www.sitepoint.com/mysql-transaction-gotchas-good-parts/
Is there any possible way to do this role back in mysql.
No. You would need to run a new alter table query undoing your previous alter statement.
do it manualy
if(!($result1 && $result2)) {
#drop table
$query1 = "drop table `status`";
$result = mysqli_query($con, $query1);
}
Would it be better to just export the data into (say) a collection of CSV files. Then modify any dataif needed to match the new structure. Then just create the database with the new structure and import the data into it.
Seems a simpler solution that trying to make an upgrader.
Under other circumstances I might be tempted to use
$result = mssql_query("INSERT INTO table (fields) VALUES (data);
SELECT CAST(scope_identity() AS int)");
but as I will be inserting user-submitted data, I want to continue to use PDO, which returns an empty array.
Unfortunately, I'm running PHP on a Linux server and using dblib to interface with Microsoft SQL Server, which doesn't support PDO::lastInsertID().
Please help!
Update to include code example
Here's the code I'm using: col1 is a field of type int identity and col2 is a datetime with a default of getdate().
// Connect to db with PDO
$pdo = new PDO( 'dblib:host=' . $host . ';dbname=' . $database . ';', $username, $password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION) );
// Connect to db with MSSQL
$sql = mssql_connect( $host, $username, $password );
mssql_select_db( $database, $sql );
// Create SQL statement
$query = "INSERT INTO [table] ( col3, col4, col5 )
VALUES ( 'str1', 'str2', 'str3' );
SELECT SCOPE_IDENTITY() AS theID;";
// Run with MSSQL
echo "Using MSSQL...\n";
$result = mssql_query( $query );
$the_id = mssql_result( $result, 0, 'theID' );
echo "Query OK. Returned ID is " . $the_id . "\n";
// Run with PDO
echo "\nUsing PDO...\n";
$stmt = $pdo->query( $query );
$result = $stmt->fetchAll( PDO::FETCH_ASSOC );
print_r( $result );
And this is what was displayed:
Using MSSQL...
Query OK. Returned ID is 149
Using PDO...
Array
(
)
I would love to find out that I'd done something stupid, rather than come up against a horrible dead end :)
You've got a few choices:
SELECT ##IDENTITY - return the last ID created by actions of the current connection, regardless of table/scope
SELECT SCOPE_IDENTITY() - last ID produced by the current connection, in scope, regardless of table
SELECT IDENT_CURRENT('name_of_table'); - last ID produced on that table, regardless of table/scope/connection
Of the three, SCOPE_IDENTITY() is the best candidate.
Maybe you are getting two rowsets returned. Try adding SET NOCOUNT ON; to eliminate the INSERT's rowset, or use $stmt->nextRowset if your driver supports it.