I have this code:
string insertSql =
"INSERT INTO aspnet_GameProfiles(UserId,GameId) VALUES(#UserId, #GameId)";
using (SqlConnection myConnection = new SqlConnection(myConnectionString))
{
myConnection.Open();
SqlCommand myCommand = new SqlCommand(insertSql, myConnection);
myCommand.Parameters.AddWithValue("#UserId", newUserId);
myCommand.Parameters.AddWithValue("#GameId", newGameId);
myCommand.ExecuteNonQuery();
myConnection.Close();
}
When I insert into this table, I have an auto_increment int primary key column called GamesProfileId, how can i get the last inserted one after this so I can use that id to insert into another table?
For SQL Server 2005+, if there is no insert trigger, then change the insert statement (all one line, split for clarity here) to this
INSERT INTO aspnet_GameProfiles(UserId,GameId)
OUTPUT INSERTED.ID
VALUES(#UserId, #GameId)
For SQL Server 2000, or if there is an insert trigger:
INSERT INTO aspnet_GameProfiles(UserId,GameId)
VALUES(#UserId, #GameId);
SELECT SCOPE_IDENTITY()
And then
Int32 newId = (Int32) myCommand.ExecuteScalar();
You can create a SqlCommand with CommandText equal to
INSERT INTO aspnet_GameProfiles(UserId, GameId) OUTPUT INSERTED.ID VALUES(#UserId, #GameId)
and execute int id = (int)command.ExecuteScalar.
This MSDN article will give you some additional techniques.
string insertSql =
"INSERT INTO aspnet_GameProfiles(UserId,GameId) VALUES(#UserId, #GameId)SELECT SCOPE_IDENTITY()";
int primaryKey;
using (SqlConnection myConnection = new SqlConnection(myConnectionString))
{
myConnection.Open();
SqlCommand myCommand = new SqlCommand(insertSql, myConnection);
myCommand.Parameters.AddWithValue("#UserId", newUserId);
myCommand.Parameters.AddWithValue("#GameId", newGameId);
primaryKey = Convert.ToInt32(myCommand.ExecuteScalar());
myConnection.Close();
}
This will work.
I had the same need and found this answer ..
This creates a record in the company table (comp), it the grabs the auto ID created on the company table and drops that into a Staff table (staff) so the 2 tables can be linked, MANY staff to ONE company. It works on my SQL 2008 DB, should work on SQL 2005 and above.
===========================
CREATE PROCEDURE [dbo].[InsertNewCompanyAndStaffDetails]
#comp_name varchar(55) = 'Big Company',
#comp_regno nchar(8) = '12345678',
#comp_email nvarchar(50) = 'no1#home.com',
#recID INT OUTPUT
-- The '#recID' is used to hold the Company auto generated ID number that we are about to grab
AS
Begin
SET NOCOUNT ON
DECLARE #tableVar TABLE (tempID INT)
-- The line above is used to create a tempory table to hold the auto generated ID number for later use. It has only one field 'tempID' and its type INT is the same as the '#recID'.
INSERT INTO comp(comp_name, comp_regno, comp_email)
OUTPUT inserted.comp_id INTO #tableVar
-- The 'OUTPUT inserted.' line above is used to grab data out of any field in the record it is creating right now. This data we want is the ID autonumber. So make sure it says the correct field name for your table, mine is 'comp_id'. This is then dropped into the tempory table we created earlier.
VALUES (#comp_name, #comp_regno, #comp_email)
SET #recID = (SELECT tempID FROM #tableVar)
-- The line above is used to search the tempory table we created earlier where the ID we need is saved. Since there is only one record in this tempory table, and only one field, it will only select the ID number you need and drop it into '#recID'. '#recID' now has the ID number you want and you can use it how you want like i have used it below.
INSERT INTO staff(Staff_comp_id)
VALUES (#recID)
End
-- So there you go. You can actually grab what ever you want in the 'OUTPUT inserted.WhatEverFieldNameYouWant' line and create what fields you want in your tempory table and access it to use how ever you want.
I was looking for something like this for ages, with this detailed break down, I hope this helps.
In pure SQL the main statement kools like:
INSERT INTO [simbs] ([En]) OUTPUT INSERTED.[ID] VALUES ('en')
Square brackets defines the table simbs and then the columns En and ID, round brackets defines the enumeration of columns to be initiated and then the values for the columns, in my case one column and one value. The apostrophes enclose a string
I will explain you my approach:
It might be not easy to understand but i hope useful to get the big picture around using the last inserted id. Of course there are alternative easier approaches. But I have reasons to keep mine. Associated functions are not included, just their names and parameter names.
I use this method for medical artificial intelligence
The method check if the wanted string exist in the central table (1). If the wanted string is not in the central table "simbs", or if duplicates are allowed, the wanted string is added to the central table "simbs" (2). The last inseerted id is used to create associated table (3).
public List<int[]> CreateSymbolByName(string SymbolName, bool AcceptDuplicates)
{
if (! AcceptDuplicates) // check if "AcceptDuplicates" flag is set
{
List<int[]> ExistentSymbols = GetSymbolsByName(SymbolName, 0, 10); // create a list of int arrays with existent records
if (ExistentSymbols.Count > 0) return ExistentSymbols; //(1) return existent records because creation of duplicates is not allowed
}
List<int[]> ResultedSymbols = new List<int[]>(); // prepare a empty list
int[] symbolPosition = { 0, 0, 0, 0 }; // prepare a neutral position for the new symbol
try // If SQL will fail, the code will continue with catch statement
{
//DEFAULT und NULL sind nicht als explizite Identitätswerte zulässig
string commandString = "INSERT INTO [simbs] ([En]) OUTPUT INSERTED.ID VALUES ('" + SymbolName + "') "; // Insert in table "simbs" on column "En" the value stored by variable "SymbolName"
SqlCommand mySqlCommand = new SqlCommand(commandString, SqlServerConnection); // initialize the query environment
SqlDataReader myReader = mySqlCommand.ExecuteReader(); // last inserted ID is recieved as any resultset on the first column of the first row
int LastInsertedId = 0; // this value will be changed if insertion suceede
while (myReader.Read()) // read from resultset
{
if (myReader.GetInt32(0) > -1)
{
int[] symbolID = new int[] { 0, 0, 0, 0 };
LastInsertedId = myReader.GetInt32(0); // (2) GET LAST INSERTED ID
symbolID[0] = LastInsertedId ; // Use of last inserted id
if (symbolID[0] != 0 || symbolID[1] != 0) // if last inserted id succeded
{
ResultedSymbols.Add(symbolID);
}
}
}
myReader.Close();
if (SqlTrace) SQLView.Log(mySqlCommand.CommandText); // Log the text of the command
if (LastInsertedId > 0) // if insertion of the new row in the table was successful
{
string commandString2 = "UPDATE [simbs] SET [IR] = [ID] WHERE [ID] = " + LastInsertedId + " ;"; // update the table by giving to another row the value of the last inserted id
SqlCommand mySqlCommand2 = new SqlCommand(commandString2, SqlServerConnection);
mySqlCommand2.ExecuteNonQuery();
symbolPosition[0] = LastInsertedId; // mark the position of the new inserted symbol
ResultedSymbols.Add(symbolPosition); // add the new record to the results collection
}
}
catch (SqlException retrieveSymbolIndexException) // this is executed only if there were errors in the try block
{
Console.WriteLine("Error: {0}", retrieveSymbolIndexException.ToString()); // user is informed about the error
}
CreateSymbolTable(LastInsertedId); //(3) // Create new table based on the last inserted id
if (MyResultsTrace) SQLView.LogResult(LastInsertedId); // log the action
return ResultedSymbols; // return the list containing this new record
}
I tried the above but they didn't work, i found this thought, that works a just fine for me.
var ContactID = db.GetLastInsertId();
Its less code and i easy to put in.
Hope this helps someone.
You can also use a call to SCOPE_IDENTITY in SQL Server.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
namespace DBDemo2
{
public partial class Form1 : Form
{
string connectionString = "Database=company;Uid=sa;Pwd=mypassword";
System.Data.SqlClient.SqlConnection connection;
System.Data.SqlClient.SqlCommand command;
SqlParameter idparam = new SqlParameter("#eid", SqlDbType.Int, 0);
SqlParameter nameparam = new SqlParameter("#name", SqlDbType.NChar, 20);
SqlParameter addrparam = new SqlParameter("#addr", SqlDbType.NChar, 10);
public Form1()
{
InitializeComponent();
connection = new System.Data.SqlClient.SqlConnection(connectionString);
connection.Open();
command = new System.Data.SqlClient.SqlCommand(null, connection);
command.CommandText = "insert into employee(ename, city) values(#name, #addr);select SCOPE_IDENTITY();";
command.Parameters.Add(nameparam);
command.Parameters.Add(addrparam);
command.Prepare();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void buttonSave_Click(object sender, EventArgs e)
{
try
{
int id = Int32.Parse(textBoxID.Text);
String name = textBoxName.Text;
String address = textBoxAddress.Text;
command.Parameters[0].Value = name;
command.Parameters[1].Value = address;
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
reader.Read();
int nid = Convert.ToInt32(reader[0]);
MessageBox.Show("ID : " + nid);
}
/*int af = command.ExecuteNonQuery();
MessageBox.Show(command.Parameters["ID"].Value.ToString());
*/
}
catch (NullReferenceException ne)
{
MessageBox.Show("Error is : " + ne.StackTrace);
}
catch (Exception ee)
{
MessageBox.Show("Error is : " + ee.StackTrace);
}
}
private void buttonSave_Leave(object sender, EventArgs e)
{
}
private void Form1_Leave(object sender, EventArgs e)
{
connection.Close();
}
}
}
There are all sorts of ways to get the Last Inserted ID but the easiest way I have found is by simply retrieving it from the TableAdapter in the DataSet like so:
<Your DataTable Class> tblData = new <Your DataTable Class>();
<Your Table Adapter Class> tblAdpt = new <Your Table Adapter Class>();
/*** Initialize and update Table Data Here ***/
/*** Make sure to call the EndEdit() method ***/
/*** of any Binding Sources before update ***/
<YourBindingSource>.EndEdit();
//Update the Dataset
tblAdpt.Update(tblData);
//Get the New ID from the Table Adapter
long newID = tblAdpt.Adapter.InsertCommand.LastInsertedId;
Hope this Helps ...
After inserting any row you can get last inserted id by below line of query.
INSERT INTO aspnet_GameProfiles(UserId,GameId)
VALUES(#UserId, #GameId);
SELECT ##IDENTITY
If you're using executeScalar:
cmd.ExecuteScalar();
result_id=cmd.LastInsertedId.ToString();
Maybe this answer helps as well as my database seems to have no column specified as "IDENTITY" (which is needed for "SELECT SCOPE_IDENTITY()" or "##IDENTITY" calls). Also my "ID" column was of type "binary(16)" so I needed to convert the output like stated below:
string returnId = BitConverter.ToString((byte[])cmd.ExecuteScalar()).Replace("-", "");
// skip the replace if you handle the hyphen otherwise
Use SELECT SCOPE_IDENTITY() in query
After this:
INSERT INTO aspnet_GameProfiles(UserId, GameId) OUTPUT INSERTED.ID VALUES(#UserId, #GameId)
Execute this
int id = (int)command.ExecuteScalar;
It will work
INSERT INTO aspnet_GameProfiles(UserId,GameId) VALUES(#UserId, #GameId)";
then you can just access to the last id by ordering the table in desc way.
SELECT TOP 1 UserId FROM aspnet_GameProfiles ORDER BY UserId DESC.
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[spCountNewLastIDAnyTableRows]
(
#PassedTableName as NVarchar(255),
#PassedColumnName as NVarchar(225)
)
AS
BEGIN
DECLARE #ActualTableName AS NVarchar(255)
DECLARE #ActualColumnName as NVarchar(225)
SELECT #ActualTableName = QUOTENAME( TABLE_NAME )
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #PassedTableName
SELECT #ActualColumnName = QUOTENAME( COLUMN_NAME )
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = #PassedColumnName
DECLARE #sql AS NVARCHAR(MAX)
SELECT #sql = 'select MAX('+ #ActualColumnName + ') + 1 as LASTID' + ' FROM ' + #ActualTableName
EXEC(#SQL)
END
Related
Info:
PHP 7.0.0
SQL Server 2014
Using sqlsrv driver
The following code may not be optimal but this is the PHP:
$nombre = strval($info->nombre);
$idPerfil = 0;
$sqlAltaPerfil = "{CALL AltaPerfil(?,?)}";
$paramsAltaPerfil = [
[$nombre, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARCHAR(50)],
[&$idPerfil, SQLSRV_PARAM_INOUT, SQLSRV_PHPTYPE_INT, SQLSRV_SQLTYPE_INT]
];
$stmtAltaPerfil = sqlsrv_query($conexion, $sqlAltaPerfil, $paramsAltaPerfil);
if($stmtAltaPerfil !== false) {
sqlsrv_next_result($stmtAltaPerfil);
$sqlAltaPerfilXExComp = "{CALL AltaPerfilXExamenComplementario(?, ?)}";
foreach($info->arrayIdExComp as $idExComp){
$idExComp = intval($idExComp);
var_dump($idExComp);
$paramsAltaPerfilXExComp = [
[$idPerfil, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT, SQLSRV_SQLTYPE_INT],
[$idExComp, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT, SQLSRV_SQLTYPE_INT]
];
$stmtAltaPerfilXExComp = sqlsrv_query($conexion, $sqlAltaPerfilXExComp, $paramsAltaPerfilXExComp);
if($stmtAltaPerfilXExComp !== false){
//bien
}
else{
$exito = false;
$erroresPhp .= print_r(sqlsrv_errors(), true);
break;
}
}
}
This is the SP:
ALTER PROCEDURE [dbo].[AltaPerfil](
#Descripcion varchar(50),
#IdPerfil int OUTPUT
) AS
BEGIN
INSERT INTO PERFILEXAMENCOMPLEMENTARIO (Descripcion) VALUES (#Descripcion)
SET #IdPerfil = ##IDENTITY
RETURN
END
I know by the error message i display in the client side that $idPerfil remains equal to 0 (line 2). The fun fact is that in SSMS the SP works just fine, but when calling it from PHP the $idPerfil isn't modified
EDIT: I found that the problem is not the code, it's a trigger in the DB that
for some reason interferes with the ##IDENTITY variable in the SP.
This is the trigger:
ALTER TRIGGER [dbo].[NombresPerfilesUnicos] ON [dbo].[PERFILEXAMENCOMPLEMENTARIO] INSTEAD OF INSERT, UPDATE AS
BEGIN
DECLARE #NombrePerfil varchar(50)
SELECT #NombrePerfil = Descripcion FROM inserted
IF EXISTS(SELECT PEC.IdPerfil FROM PERFILEXAMENCOMPLEMENTARIO PEC WHERE Descripcion = #NombrePerfil)
PRINT 'ERROR, la descripcion ' + #NombrePerfil + ' ya esta registrada'
else
INSERT INTO PERFILEXAMENCOMPLEMENTARIO SELECT Descripcion FROM inserted
END
So my new question is: Why this is happening? What do i have to do to keep this trigger working (modify if necessary) and make everything work?
Try using SCOPE_IDENTITY() instead of ##Identity.
Sourced from :
http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/
"SELECT ##IDENTITY
It returns the last IDENTITY value produced on a connection, regardless of the table that produced the value, and regardless of the scope of the statement that produced the value."
"SELECT SCOPE_IDENTITY()
It returns the last IDENTITY value produced on a connection and by a statement in the same scope, regardless of the table that produced the value."
You can use in the following way: and you don't need second variable if you don't have any transaction with that next in the stored procedure.Using IDENT_CURRENT with table name is much better than others because it just return you identity value of mentioned table.
--Procedure Part
ALTER PROCEDURE [dbo].[AltaPerfil](
#Descripcion VARCHAR(50)
) AS
BEGIN
INSERT INTO PERFILEXAMENCOMPLEMENTARIO(Description) VALUES (#Descripcion)
SELECT IDENT_CURRENT('PERFILEXAMENCOMPLEMENTARIO') AS rowID
END
--Call From PHP replace with your variable and It will return your column rowID with value:
EXEC AltaPerfil 'test'
In the end, all i had to do was adding SET NOCOUNT ON to the SP and it magically worked
ALTER PROCEDURE [dbo].[AltaPerfil](
#Descripcion varchar(50),
#IdPerfil int out
) AS
BEGIN
SET NOCOUNT ON;
INSERT INTO PERFILEXAMENCOMPLEMENTARIO (Descripcion) VALUES (#Descripcion)
SET #IdPerfil = ##IDENTITY
END
I have a Mysql table where pincode field cant be duplicate daily (Sequential increment id), also i cant apply the unique key on that field using Mysql indexing for some reason.
Using PHP i am trying as below, but my code will become endless if i have to keep increasing by checking them as below.
Is there any better way without Mysql indexing to do it from PHP (zend framework)?
$sql = "SELECT count(*) as total
FROM `sh_av_spform`
WHERE DATE(`createdate`) = CURDATE( )";
$result = $db->fetchAll($sql);
if(count($result)>0) {
$tmp_id = $result[0]['total'] +1;
$new_id = sprintf('%03d',$tmp_id); // 009
try{
$sql1 = "SELECT id,pincode
FROM `sh_av_spform`
WHERE DATE(`createdate`) = CURDATE() and pincode='$new_id' limit 1";
$result1 = $db->fetchAll($sql1);
if(count($result1)>0) {
// 009 already exist make it 010?
$tmp_id = $result[0]['total'] +2;
$new_id = sprintf('%03d', $tmp_id); // 010
}
// Ooopsssss! 010 also exist. now what?
// keep wrting code forever? or there is better way?
$db->insert('sh_av_spform', array('pincode'=>$new_id) );// Pincode cant be duplicated
You can do this entirely in database, using a counter table.
Example:
CREATE TABLE daily_pin (day DATE PRIMARY KEY, pin INT UNSIGNED);
START TRANSACTION;
INSERT INTO daily_pin VALUES (CURDATE(),1) ON DUPLICATE KEY UPDATE pin=LAST_INSERT_ID(pin+1);
INSERT INTO table_requiring_pin (pin) VALUES (LPAD(LAST_INSERT_ID(),3,'0'));
COMMIT;
Notes:
The counter table holds a given day's highest as yet used PIN.
The INSERT .. ON DUPLICATE KEY gets a new pin, either a "1" if it's the first entry for a given day, or the current value plus 1.
LAST_INSERT_ID, when given an argument, returns the argument and remembers it for the next time LAST_INSERT_ID is called without an argument.
Finally, left pad it with LPAD to get the "000" format you're wanting.
As a side benefit of this approach, you get easy metrics on pin usage. Like, "what day of the week consumes the most pin?"
You can create one separate function for checking pin code before you insert.
For example
public function ValidatePinCode($PinCode){
if(isset($PinCode)){
$SQL=$db->prepare("SELECT pincode FROM `sh_av_spform` WHERE pincode='".$PinCode."'");
$SQL=$db->execute($SQL);
if($SQL->fetchColumn()>0){
$ResponseCode='FALSE';
}else {
$ResponseCode='TRUE';
}
return $ResponseCode;
}
}
If you get FALSE response then do not allow to insert new pin code else you can perform INSERT query.
Let me know if you want even more explanation on this.
I want to create columns in a MySQL table and insert data into them. I already have some data inside of the table, I would like to add more. I am not sure how I would go about adding the other data. If someone could help me out, I would greatly appreciate it. Thanks.
My Source code looks like this:
if($is_array($asinXML){
foreach($asinXML as $asinXml){
$asinXmlLoaded = simplexml_load_file($asinXml);
foreach($asinXml->GetLowestOfferListingsForASINResult as $asinItem){
if(isset($asinItem['ASIN'])){
$asinValue = $asinItem['ASIN'];
} else {
$asinValue = '';
}
$asinErrorFound = 'Success' != $asinItem->attributes()->status;
if($asinErrorFound = TRUE){
$asinErrorFoundVal = 'Yes';
} else {
$asinErrorFoundVal = '';
}
if($asinErrorFoundVal == ''){
if(isset($asinItem->Product->LowestOfferListing->NumberOfOfferListingsConsidered){
$numberOfSellers = $asinItem->Product->LowestOfferListings->LowestOfferListing->NumberOfOfferListingsConsidered;
} else {
$numberOfSellers = '';
}
My Sql table looks something like this so far :
UPC ASIN SalesRank
Value Value1 Value2
I need to be able to insert a insert another column, then populate the column with information that corresponds to the ASIN Value. If that doesn't make sense, comment and i will elaborate. Thanks.
You can add a column (or columns) using ALTER TABLE statement. e.g.
ALTER TABLE mytable ADD my_new_col INT COMMENT 'my new column' ;
If you want to initialize that column on all of the rows that are already in the table, you can populate it with the value from another column on the row with an UPDATE statement:
UPDATE mytable SET my_new_col = some_old_col ;
If you just want to add a new row to the table, you can use the INSERT statement:
INSERT INTO mytable (my_new_col) VALUES (42);
you can ADD a calculated Column with the desired value.
If ASIN is numeric and you want to add taxes
ALTER TABLE myTable ADD MyNewColumn AS (ASIN * 1.08)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
MySQL trigger to update a field to the value of id
Please I have a table with three fields :
Id (auto increment)
GroupById
Text
And I want when inserting a new row : If I left the field groupById blank, it must get by default the same value of the field Id.
Please have you any Idea ? Thanks in advance.
Edit : My code :
mysql_query("INSERT INTO group SET GroupById = (must get the current Id), Text = 'bla bla bla' ");
How about a trigger:
DELIMITER $$
CREATE TRIGGER trg_yourtable
BEFORE INSERT ON yourtable
FOR EACH ROW
BEGIN
IF NEW.GroupById IS NULL THEN
SET NEW.GroupById = (
SELECT AUTO_INCREMENT
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'yourtable'
);
END IF;
END $$
I'm not sure how safe this is... or what happens when you insert multiple rows from one query, or when two connections attempt to insert at the same time... but it works.
This simple SQL should do what you want:
INSERT INTO myTable (GroupById, Text) VALUES (NULL, 'your text');
SET #lastID = LAST_INSERT_ID();
UPDATE myTable SET GroupById = #lastID WHERE Id = #lastID;
Use a stored procedure
Get the MAX id
Add 1 to it and add insert it into both rows
You get the desired result in a single transaction.
Hope this helps.
Use this function | Tested
Example of use:
function get_current_insert_id($table)
{
$q = "SELECT LAST_INSERT_ID() FROM $table";
return mysql_num_rows(mysql_query($q)) + 1;
}
$txt = "text";
$groupID = '';
if ( empty($groupID) ) { $groupID = get_current_insert_id(test); }
$query = mysql_query("INSERT INTO test VALUES ('', '$groupID', '$txt') ");
if ( $query ) { echo 'Saved using ID:' . $groupID; } else { echo 'Oh noes!' . $query; }
Looks like you might need to run 2 queries:
insert into 'table' ('GroupById', 'Text') VALUES ('{group id}', '{sometext}')
update 'table' set GroupById = id where GroupById = null - it mightbe 0 instead of null depending on what you insert in db.
You can always optimize it through indexes, limits, order.
The current value for the columns countProductSelect and countProductInput - INTEGER NOT NULL;
Need to make INTEGER DEFAULT NULL;
PHP code below.
The problem is that when trying to update data and countProductSelect countProductInput, from the time column and countProductSelectTmp countProductInputTmp, getting the error - "no such column: countProductSelectTmp".
How to deal with this error? Or perhaps there is more educated algorithms for solving the original problem?
/**
* Updating the database
*
* #return bool
*/
protected function _updateDB()
{
$version = '3.8.4.0';
$this->_pdo->exec('
ALTER TABLE data ADD optionalCountProduct INTEGER DEFAULT NULL;
ALTER TABLE data ADD countProductSelectTmp INTEGER DEFAULT NULL;
ALTER TABLE data ADD countProductInputTmp INTEGER DEFAULT NULL;
UPDATE data SET countProductSelectTmp = countProductSelect, countProductInputTmp = countProductInput;
');
$this->_deleteSQLiteColumn(array('countProductSelect', 'countProductInput'));
// BUG
// countProductSelect and countProductInput can not get the value countProductSelectTmp and countProductInputTmp
$this->_pdo->exec('
ALTER TABLE data ADD countProductSelect INTEGER DEFAULT NULL;
ALTER TABLE data ADD countProductInput INTEGER DEFAULT NULL;
UPDATE data SET countProductSelect = countProductSelectTmp, countProductInput = countProductInputTmp;
UPDATE version SET id = "' . $version . '";
');
$this->_deleteSQLiteColumn(array('countProductSelectTmp', 'countProductInputTmp'));
return true;
}
/**
* Remove column from a SQLite Table
*
* #param array $column name of the column to remove
* #return bool
*/
protected function _deleteSQLiteColumn(array $column)
{
return (bool)$this->_pdo->exec('
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE backup(' . $this->_getFullColumnsString() . ');
INSERT INTO backup SELECT ' . $this->_getShortColumnsString() . ' FROM data;
DROP TABLE data;
CREATE TABLE data(' . $this->_getFullColumnsString($column) . ');
INSERT INTO data SELECT ' . $this->_getShortColumnsString($column) . ' FROM backup;
DROP TABLE backup;
COMMIT;
');
}
From the fine manual:
PDO::exec — Execute an SQL statement and return the number of affected rows
But you're trying to execute multiple statements at once so perhaps it is only executing the last statement. Trying using exec as intended and executing your statements one at a time:
$this->_pdo->exec('ALTER TABLE data ADD optionalCountProduct INTEGER DEFAULT NULL');
$this->_pdo->exec('ALTER TABLE data ADD countProductSelectTmp INTEGER DEFAULT NULL');
$this->_pdo->exec('ALTER TABLE data ADD countProductInputTmp INTEGER DEFAULT NULL');
$this->_pdo->exec('UPDATE data SET countProductSelectTmp = countProductSelect, countProductInputTmp = countProductInput');
And then again with your next multi-statement exec and your _deleteSQLiteColumn.
As far as a better way goes, it looks like all you want to do is drop the NOT NULL constraint but SQLite's ALTER TABLE is a bit limited so your "add column, copy column, drop column via table copying" approach is the best you can do; from the SQLite FAQ:
For example, suppose you have a table named "t1" with columns names "a", "b", and "c" and that you want to delete column "c" from this table. The following steps illustrate how this could be done:
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE t1_backup(a,b);
INSERT INTO t1_backup SELECT a,b FROM t1;
DROP TABLE t1;
CREATE TABLE t1(a,b);
INSERT INTO t1 SELECT a,b FROM t1_backup;
DROP TABLE t1_backup;
COMMIT;