SQL query to update column in a table - sql

I have a code based website in which an employee has to update their reward points by the coupon code provides them and when that code reflect their account means when points are updated in their account they are able to shop in the website. But there is a restriction for the code that code is deleted once used. Sometimes I found a query from customers that they update their account with the code provided but code did not reflect the account and deleted from the database and so thereafter they are not able to use the code again now I want that code only deleted when the code update points in their account. I have an another table named customer_reward where code saved after add points in the customers account but the code that not reflect account recharge is not saved in that table so I want that code only delete when that code is saved in the customer_reward table.
the complete code is given below:
<?php
if(isset($_POST['sub'])){
$db_host="localhost";
$db_username="root";
$db_password="";
$db_name="14";
$con=mysql_connect("$db_host", "$db_username", "$db_password") or die("could not connect to mysql!!!");
if($con=="")
{
echo "Database not connected!!!!";
}
else
{
$isdb=mysql_select_db("$db_name") or die("database not available!!!!");
if($isdb=="")
{
echo "database not selected!!!!";
}
else
{
$emp_ID=$_POST['emp_ID'];
$code=$_POST['code'];
$query = mysql_query("select * from oc_abhireward where `Code`='$code'") or die (mysql_error());
$data=mysql_fetch_assoc($query);
$code_db=$data['Code'];
$points_db=$data['Point'];
if($code==$code_db)
{
$query1 = mysql_query("select * from oc_customer where `emp_ID`='$emp_ID'") or die (mysql_error());
$data1=mysql_fetch_assoc($query1);
$customer_id=$data1['customer_id'];
$query2=mysql_query("INSERT INTO `oc_customer_reward` (customer_id, order_id, description, Code, points, date_added) VALUES ($customer_id, 0, 'rewarded', '$code', $points_db, NOW());");
$query4=mysql_query("INSERT INTO `oc_customer_recharge`(emp_ID, Code, points, date_added) VALUES ('$emp_ID', '$code', $points_db, NOW());");
if ($code==$code_db)
{
query5 = mysql_query("select * from oc_customer_recharge where Code='$code'")or die (mysql_error());
$data2=mysql_fetch_assoc($query4);
$emp_ID=$data2['emp_ID'];
$query6 = mysql_query("DELETE FROM oc_abhireward WHERE Code='$code'");
}
else
{
exit();
}
header("location:http://localhost/14/index.php?route=account/account");
exit();
}
else
{
}
}
}
}
?>

What's the relationship between Employee and Customer?
You are querying oc_customer by emp_ID, and getting customer_id from it. So is oc_customer unique on emp_id? If not, then the customer you end up getting (and so the one you'll apply the reward to) is effectively random. Instead, you need to pass in the customer's customer_id rather than the emp_id.
One other thing; You're using the "$POST"ed values directly in the SQL statements. That opens you up to a SQL-Injection attack. Check out How can I prevent SQL injection in PHP?

The best way possible here could be creating a trigger (for deleting the code) that will fired only when the update of points has been made.
CREATE TRIGGER trigger_name
AFTER INSERT
ON table_name FOR EACH ROW
BEGIN
-- logic for deleting the corresponding CODE
END;
Hope this will bring you closer to what you seek.
Ak

I think the problem is that you are really not veryfing whether a record was inserted in your oc_customer_reward table.
There are multiple ways of solving this problem.
You can modify your delete query to check oc_customer_reward table. This could be something on the lines of:
DELETE Table1
FROM Table1
INNER JOIN Table2 ON Table1.ID = Table2.ID
Create a trigger which will delete data in oc_reward table whenever a record is inserted in oc_customer_reward. You can look up triggers here
CREATE TABLE reward_code_table
(reward_code INT, random_col VARCHAR(50))
;
INSERT INTO reward_code_table
(`reward_code`, `random_col`)
VALUES
(1, 'First code'),
(2, 'Second code'),
(3, 'Third code')
;
CREATE TABLE insert_code_table
(customer_code INT, another_random_col VARCHAR(50))
;
DELIMITER //
CREATE TRIGGER del_after_insert
AFTER INSERT
ON insert_code_table
FOR EACH ROW
BEGIN
DELETE FROM reward_code_table WHERE reward_code = NEW.customer_code;
END;
//
DELIMITER ;
INSERT INTO insert_code_table(customer_code, another_random_col)
VALUES (2, "del 2 from reward table");
After inserting into one table, it deletes record from the other table.
You can checkout a sample SQLFiddle. Note that I have kept the delimiter as // in the fiddle example
Also consider using prepared statements to prevent basic mysql injections.

Related

Checking some columns for specific values before insert/update using a trigger

I have a database FOO with several columns, among those I have one column "Url". I need to write a trigger before insert/update that will check the Url columns whether the newer value matches any existing values, i.e. "hello" except some predefined value. That means if "hello" is inserted or updated multiple times no error will happen otherwise it will check for duplicity. And if it finds some aborts the insertion update. This will also return some code so that my script calling for the insertion/update will know a failure has occurred. I know there might be other workarounds but I will need to have it this way. I am pretty new to SQL.
Foo {
Url
}
Here is the algorithm
Before update insert
if new value of Url is not "hello1" o "hello 2"
check if new value of Url already exists in Foo.Url if so abort otherwise allow update/insert
return something if aborted/success
try something like this.. you'll need to index your table..
IF EXISTS(SELECT URL FROM Foo.Url)
BEGIN
SELECT 'URL Exists Already'
END
ELSE
BEGIN
INSERT/UPDATE
END
A unique constraint wouldn't do what you want but you could create an instead of trigger with content something like as:
Create TRIGGER [dbo].[Trig_Insert_XXX]
ON [dbo].[XXX]
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO xxx ([url], field1, field2, fieldN)
SELECT [url], field1, field2, fieldN
FROM inserted i
WHERE i.url = 'hello' OR NOT EXISTS (SELECT * FROM xxx t2 WHERE t2.url = i.url);
END;
I suppose you're looking for a UNIQUE constraint & a CHECK constraint as
CREATE TABLE Foo(
Url VARCHAR(250) NOT NULL,
CONSTRAINT UQ_Url UNIQUE(Url),
CONSTRAINT CHK_Url CHECK (Url NOT IN ('hello1', 'hello2'))
);
See how it's working online.
If you are using SQL Server 2008 or newer version you can use MERGE as well, the syntax is like the following :
MERGE [TableName] AS TARGET
USING ( SELECT #UrlName ) AS SOURCE (UrlName) ON SOURCE.UrlName = TARGET.UrlName
WHEN MATCHED THEN
UPDATE SET ...
WHEN NOT MATCHED THEN INSERT ()
VALUES ();

Tablegateway "insert" gets executed but no values are written into table

Environment: Docker container, where PHPand MySQL runs in seperated containers
I have a table "persons" and want to insert values using TableGateway. The code gets executed and I can catch the last inserted value. It's an autoincrement and every performed insert on this table increments this value.
But no values are saved in the table (e.g. phone)
public function __construct(
...
TableGateway $tablePersons,
...
) {
...
$this->tablePersons = $tablePersons;
...
}
...
$this->tablePersons->insert(['phone' => 123456]);
$id = $this->tablePersons->lastInsertValue;
I printed the sql string out and it looks fine.
$sql = $this->tablePersons->getSql();
$insert = $sql->insert();
$insert->values(['phone' => 123456]);
print $sql->buildSqlString($insert);
// Result: INSERT INTO `persons` (`phone`) VALUES ('123456')
I performed this query on phpmyadmin and everthing looks good, values are stored.
mysql_error.log is empty
mysql.log shows the following:
2019-05-12T23:34:20.940510Z 34 Connect root#172.20.0.5 on app using TCP/IP
2019-05-12T23:34:20.940795Z 34 Query SET AUTOCOMMIT=0
2019-05-12T23:34:20.943878Z 34 Query INSERT INTO `persons` (`phone`) VALUES (42)
2019-05-12T23:34:20.944329Z 34 Quit
To bypass the zend-framework, I went to the index.php and performed a classic mysqli query:
$conn = new mysqli(## same values as in the zend-db adapter config ##);
$sql = "INSERT INTO persons (phone) VALUES (123456)";
$conn->query($sql);
This works perfectly fine - a new row gets stored. So I think, a problem with the environment may be excluded.
I need a hint, an idea why the values are not saved when I run the query with the framework functions.
Try to confirm that you' ve to initiated a database transaction that is preventing AUTO_COMMIT of the inserted values. Also, confirm that the field length for the phone and other fields are large enough to store the values passed.

Use trigger after multiple insert to update log table

I have the following trigger:
ALTER TRIGGER [Staging].[tr_UriData_ForInsert]
ON [Staging].[UriData]
FOR INSERT
AS
BEGIN
DECLARE #_Serial NVARCHAR(50)
DECLARE #_Count AS INT
IF ##ROWCOUNT = 0
RETURN
SET NOCOUNT ON;
IF EXISTS(SELECT * FROM inserted)
BEGIN
SELECT #_Count = COUNT(Id) FROM inserted
SELECT #_Serial = SerialNumber FROM inserted
INSERT INTO [Staging].[DataLog]
VALUES (CURRENT_TIMESTAMP, #_Serial + ': Data Insert --> Rows inserted: ' + #_Count, 'New data has been received')
END
END
The table receives multiple rows at once. I want to be able to add one row in the log table to tell me the insert has happened.
It works great with one row being inserted, but with multiple rows, the trigger doesn't fire. I have read other items on here and it is quite clear that you shouldn't use ROW_NUMBER().
In summary: I want to update my log table when a multiple row insert happens in another table called UriData.
The data is inserted from C# using the following:
using (var sqlBulk = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, transaction))
{
sqlBulk.DestinationTableName = tableName;
try
{
sqlBulk.WriteToServer(dt);
}
catch(SqlException sqlEx)
{
transaction.Rollback();
var msg = sqlEx.Message;
return false;
}
finally {
transaction.Commit();
conn.Close();
}
}
I don't want to know what is being inserted, but when it has happened, so I can run a set of SPROCS to clean and pivot the data.
TIA
The problem is your trigger assumes that only one row will be updated. A scalar variable can only have 1 value. So, for example, the statement SELECT #_Serial = SerialNumber FROM inserted will set #_Serial with the last value returned from the object inserted.
Treat your data as what it is, a dataset. This is untested, however, I suspect this gives you the result you want:
ALTER TRIGGER [Staging].[tr_UriData_ForInsert]
ON [Staging].[UriData]
FOR INSERT
AS
BEGIN
--No need for a ROWCOUNT. If there are no rows, then nothing was inserted, and this trigger won't happen.
INSERT INTO [Staging].[DataLog] ({COLUMNS LIST})
SELECT CURRENT_TIMESTAMP,
SerialNumber + ': Data Insert --> Rows inserted: ' +
CONVERT(varchar(10),COUNT(SerialNumber) OVER (PARTITION BY SerialNumber)), --COUNT returns an INT, so this statement would have failed with a conversion error too
'New data has been received'
FROM inserted;
END
Please note my comments or sections in braces ({}).
Edit: Sean, who has since deleted his answer, used GROUP BY. I copied what exact method you had, however, GROUP BY might well be the clause you want, rather than OVER.
So after a lot of digging and arguing, my hosting company told me that they have disabled bulk inserts of any kind, without bothering to notify their customers.

Insert trigger preventing duplicates

I have a table with a AutoIdentity column as its PK and a nvarchar column called "IdentificationCode". All I want is when inserting a new row, it will search the table for any preexisting IdentificationCode, and if any found roll back the transaction.
I have written the folowing trigger:
ALTER trigger [dbo].[Disallow_Duplicate_Ids]
on [dbo].[tbl1]
for insert
as
if ((select COUNT(*) from dbo.tbl1 e , inserted i where e.IdentificationNo = i.IdentificationNo ) > 0)
begin
RAISERROR('Multiple Ids detected',16,1)
ROLLBACK TRANSACTION
end
But when inserting new rows, it always triggers the rollback even if there is no such IdentificationCode.
Can any one help me please?
thanks
As #Qpirate mentions, you should probably put some sort of UNIQUE constraint on the column. This is probably 'stronger' than using a trigger, as there's ways to disable those.
Also, the implicit-join syntax (comma-separated FROM clause) is considered an SQL anti-pattern - if possible, please always explicitly declare your joins.
I suspect that your error is because your trigger seems to be an AFTER trigger, and you check to see if there are any (non-zero) rows in the table; in other words, the trigger is (possibly) 'failing' the INSERT because it was INSERTed. Changing it to a BEFORE (or INSTEAD OF) trigger, or changing the count to >= 2 may solve the problem.
Without seeing your insert statement, it's impossible to know for sure, but (especially if you're using a SP), you may be able to check for existence in the INSERT statement itself, and throw an error (or do something else) if the row isn't inserted.
For example, the following:
INSERT INTO tbl1 (identificationCode, *otherColumns*)
VALUES (#identificationCode, *otherColumns)
WHERE NOT EXISTS (SELECT '1'
FROM tbl1
WHERE identificationCode = #identificationCode)
Will return a code indicating 'row not found' (inserted, etc; on pretty much every system this is SQLCODE = 100) if identificationCode is already present.
Use EXISTS to check if the IdentificationCode already exist.
If EXISTS (Select * from tbl1 where IdentificationCode = #IdentificationCode )
BEGIN
//do something
END
Else
BEGIN
//do something
END

How to get IDs for bulk inserts in codeigniter?

In Codeigniter, if I create an SQL string which does multiple inserts, how do I get the inserted id of each?
// Prepare the SQL
$sql = '';
$chunk = array(array(), array(), array()); // The elements are arrays
foreach($chunk as $arr){
// The first field is the primary key (INT NOT NULL auto_increment)
$sql .= "(NULL, {$arr[0]}, {$arr[1]}, {$arr[2]}, {$arr[3]}, {$arr[4]})";
if($arr!= $last) $sql .= ', ';
}
// Start inserting into the db
$this->db->trans_start();
$this->db->query('INSERT INTO my_table VALUES '.$sql);
// A few other queries go here which need the IDs of the previous insert
$this->db->trans_complete();
This is also my first time using transactions.
You probably need to record the MAX id before the insert, and then select all the ids greater than that after the bulk insert.
EDIT:
I found this in the MySQL manual:
The correct way to use LOCK TABLES and UNLOCK TABLES with transactional tables, such as InnoDB tables, is to begin a transaction with SET autocommit = 0 (not START TRANSACTION) followed by LOCK TABLES, and to not call UNLOCK TABLES until you commit the transaction explicitly.
I decided to go with using transactions instead.