I'm using PHP to send a query to Sql Server. The problem is, my "SELECT 1 AS updateResults" statement doesn't work if it's done after the UPDATE statement. A resource is returned to PHP but it doesn't have any rows.
Here's a simplified version of my query:
--SELECT 1 AS updateResults --if this is done before the UPDATE, a row gets returned
UPDATE theTable SET theValue = 'x' WHERE theRow = '5'
SELECT 1 AS updateResults --if this is done after the UPDATE, a row doesn't get returned
My UPDATE query is valid and does what it's supposed to do.
I've also tried the "SELECT 'updateResults' = 1" format and tried putting a ; at the end of each statement and it didn't make a difference.
Any ideas?
Here's the PHP code:
$updateSQL = "BEGIN TRANSACTION
DECLARE #result1 int
DECLARE #result2 int
--SELECT 1 AS updateResults --if this is here, the row gets returned
UPDATE theTable
SET endDate = '" . $endDate . "'
WHERE permitYear = '" . $permitYear . "'
UPDATE theTable
SET startDate = '" . $startDate . "'
WHERE permitYear = '" . $nextYear . "'
--Test to make sure both records were saved
SELECT #result1 = permitYear
FROM theTable
WHERE permitYear = '" . $permitYear . "'
AND endDate = '" . $endDate . "'
SELECT #result2 = permitYear
FROM theTable
WHERE permitYear = '" . $nextYear . "'
AND startDate = '" . $startDate . "'
if ((#result1 > 0) AND (#result2 > 0))
BEGIN
COMMIT TRANSACTION
SELECT 1 AS updateResults
END
ELSE
BEGIN
ROLLBACK TRANSACTION
SELECT 0 AS updateResults
END";
$updateRS = sqlsrv_query($con, $updateSQL);
if (!is_resource($updateRS)) {
//There was a problem. A resource wasn't returned. It never fails here
exit;
}
if (!sqlsrv_has_rows($updateRS)) {
echo ("fail for no rows returned");
exit;
}
$updateARR = sqlsrv_fetch_array($updateRS);
//It makes it here if the SELECT is done before the UPDATE
if ($updateARR['updateResults'] == '1') {
//success
}
else {
//save problem
}
Additional info: If I take out the 2 UPDATE statements it runs as expected and returns the updateResults row.
You should query select like this
SELECT * FROM table1 WHERE 'updateResults' = 1
I ended up doing this in two SQL statements rather than one. Here's what I did:
I took out the SELECT x AS updateResults lines from the $updateSQL then:
$updateSQL = ...(same as the question, without the SELECT x AS updateResults lines)...
sqlsrv_query($con, $updateSQL);
$testSQL = "
DECLARE #result1 int
DECLARE #result2 int
SELECT #result1 = permitYear
FROM theTable
WHERE permitYear = '" . $permitYear . "'
AND endDate = '" . $endDate . "'
SELECT #result2 = permitYear
FROM Transportation.dbo.PermitDate
WHERE permitYear = '" . $nextYear . "'
AND startDate = '" . $startDate . "'
if ((#result1 > 0) AND (#result2 > 0))
BEGIN
SELECT 1 AS updateResults
END
ELSE
BEGIN
SELECT 0 AS updateResults
END
";
$testRS = sqlsrv_query($con, $testSQL);
if (!is_resource($testRS)) {
//There was a problem. A resource wasn't returned
}
if (!sqlsrv_has_rows($testRS)) {
//fail for no rows
}
$testARR = sqlsrv_fetch_array($testRS);
if ($testARR['updateResults'] == '1') {
//success
}
else {
//fail - the changes were not saved
}
Did you try to reverse the order of the SELECT and UPDATE statements when they're part of the transaction? If not, I would try:
Instead of:
COMMIT TRANSACTION
SELECT 1 AS updateResults
Try:
SELECT 1 AS updateResults
COMMIT TRANSACTION
I didn't have "SET NOCOUNT ON" so the SQL messages such as "(1 row(s) affected)" were being returned before the SELECT results. My code should have been:
$updateSQL = "SET NOCOUNT ON
BEGIN TRANSACTION
...
This way the SQL messages would be supressed.
As a side note, after I figured out the issue I noticed the following: Even though I wasn't using a stored procedure for this, I noticed when you create a stored procedure in SQL Server Management Studio, it even puts the following in the template for you:
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Related
I must to send an INSERT query to MySQL database, assuming all the variables are correctly setted, I'm using this code:
$check_alrd_sent = $mysqli -> query("SELECT * FROM reviews WHERE id_prod =" . $id_prod . " AND id_user = " . $current_usr . " LIMIT 1");
$check = mysqli_fetch_all($check_alrd_sent);
if ($check != NULL) {
$check_err = 1;
} else {
$ins_rev = $mysqli -> query("INSERT INTO `reviews` (`ID` ,`ID_prod` ,`ID_user` ,`review` ,`stars`) VALUES (NULL , " . $id_prod .", " . $current_usr . ", " . $review . ", " . $rating . ");");
$ins_result = 1;
}
mysqli_free_result($check_alrd_sent);
The $ins_result variable is correcly set as result, as I can see using var_dump() but now rows are insert in database.
The strange thing is that if I call the MySQL error log can clearly see that the insert is sent to the database correctly as:
42 Query INSERT INTO `reviews` (`ID` ,`ID_prod` ,`ID_user` ,`review` ,`stars`) VALUES (NULL , 11, 1, asd, 4)
But it doesn't appear in the table.
Any suggestions? Thanks
You have two issues in your INSERT Statement:
Value of review column is a string so you need to use quotes around review VALUE.
I think ID is an AUTO INCREMENT NOT NULL field. So no need to use in INSERT Query.
Modified query:
INSERT INTO `reviews`
( `ID_prod`, `ID_user` ,`review` ,`stars`)
VALUES (11, 1, "asd", 4)
varchar fields must be in 2 quota, so review field must be in 2 ':
$ins_rev = $mysqli -> query("INSERT INTO `reviews` (`ID` ,`ID_prod` ,`ID_user`
,`review` ,`stars`) VALUES (NULL , '" . $id_prod ."', ' " . $current_usr . "', '" .
$review . "', '" . $rating . "');");
In your output, "asd" is not in single quotes. That would be invalid SQL. Should also think about converting to non-deprecated SQL functions such as PDO.
i have a php script for bulk update, in my database exists 90,585 rows but only update 85,282 rows, and i don't know why, this is my script:
//limit the select to 100
//Bulk update is very slow, is you set a limit very high server crash
$limit = 100;
//$messages = array();
$updated_posts = 0;
//maybe there are better solutions for this
for ($i=0;$i<=$totalMsg;$i+=$limit)
{
$get_posts = mysqli_query($conn,
"SELECT id_msg, body
FROM " . $to_prefix ."messages
WHERE id_msg != 0
LIMIT " . $i ."," . $limit);
//The post Array
$messages = array();
while($row = mysqli_fetch_assoc($get_posts))
{
$messages[$row['id_msg']] = array(
'body' => fixBBCTags($row['body']),
);
}
//update data!, good luck!!
bulkUpdate($conn,$to_prefix."messages","id_msg","body",$messages);
$updated_posts += mysqli_affected_rows($conn);
}// for loop
this is the bulkUpdate() function:
function bulkUpdate($conn, $table, $id_column, $update_column, array &$idstovals)
{
global $error;
//prepare the Bulk Update SQL
$sql = "update " . $table . " set " . $update_column . " = CASE " . $id_column ;
foreach($idstovals as $id => $val)
{
$sql .= " WHEN " . "'" . $id . "'" . " THEN " . "'" . mysqli_real_escape_string($conn,$val[$update_column]) . "'" . " \n";
}
$sql .= " END
WHERE " . $id_column. " in (" . implode(',', array_keys($idstovals)) . ")";
//reset the array
//$idstovals=array();
//try update the bulk
$update = mysqli_query($conn,$sql);
if(mysqli_error($conn))
$error = mysqli_error($conn);
}
All the rows must be updated, there are better solution for this?
Regards.
When you wrote the same data in a row, MySQL do not write this record
MariaDB [test]> create table r (id integer, PRIMARY KEY (id) );
Query OK, 0 rows affected (0.15 sec)
MariaDB [test]> insert into r (id) VALUES (1),(2),(3);
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
MariaDB [test]> update r set id=4 where id=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [test]> update r set id=4 where id=4;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
Here my second try,
UPDATE updatetable u
LEFT JOIN reftable r ON r.id = p.id
SET u.updatecol = r.refcol
WHERE r.id_msg !=0 ;
Or you build a array in PHP with id (PRIMARY KEY) and new values. So you can generate a bulk INSERT with ON DUPLICATE KEY UPDATE like this
INSERT INTO mytable (id,col) VALUES
(1,'new val'),
(2,'new val'),
(3,'new val'),
(66,'new val'),
...
(80000,'new val for id 80000')
ON DUPLICATE KEY UPDATE col= VALUES(col);
Sorry am late, here my Answer.
Here is a Sample. I h dont test it. It is importent that the Column id_msg is the PRIMARY KEY or have a unique INDEX.
//limit the select to 100
//Bulk update is very slow, is you set a limit very high server crash
$limit = 100;
$messages = array();
$updated_posts = 0;
$get_posts = mysqli_query($conn,
"SELECT id_msg, body FROM " . $to_prefix ."messages WHERE id_msg != 0");
while($row = mysqli_fetch_assoc($get_posts))
{
$messages[] = "('".$row['id_msg'] ."','"
.mysqli_real_escape_string(fixBBCTags($row['body'])) ."')";
}
$sql_pre = "INSERT INTO ".$to_prefix.".messages (id_msg,message) VALUES "
$sql_post = " ON DUPLICATE KEY message = VALUE(message)"
$sql = "";
$sep = "";
$cnt = 0;
foreach($messages as $msg)
{
$sql = $sep . $msg;
$sep = ",";
if ($cnt++ % $limit) {
mysqli_query($conn,$sql_pre . $sql . $sql_post);
$pre = "";
}
}
// Write the Rest if one
if ( $sql <> "" ) {
mysqli_query($conn,$sql_pre . $sql . $sql_post);
}
I am trying to do an Oracle insert statement on a PHP page but I am getting the error below. If I remove the semicolon from the statement, the page never loads (even though the insert on the backend should take a fraction of a second). Any tips would be greatly appreciated!
$sql_update = "
update schema.table set last_check_dt = (select sysdate from dual)
where id = (select id from schema.email where current_email = '" . $email . "');";
$stid = oci_parse($conn, $sql_update);
oci_execute($stid);
oci_commit($conn);
oci_close($conn);
Warning: oci_execute() [function.oci-execute]: ORA-00911: invalid character
$sql_update = "
update schema.table set last_check_dt = (select sysdate from dual)
where id = (select id from schema.email where current_email = '" . $email . "')";
Your SQL, when run through a OCI.. Don't need a semicolon as terminator.
I have a comment section and a reply to comment section on my social network. We are having some trouble with manual spammers, and I was going to limit the amount of comments someone could post a day.
Here are the insert queries for comments and reply to comments:
//COMMENTS
$query = "INSERT INTO `CysticAirwaves` (
`FromUserID`,
`ToUserID`,
`comment`,
`status`,
`statusCommentAirwave`,
`date`,
`time`
) VALUES (
'" . $auth->id ."',
'" . $prof->id ."',
'" . mysql_real_escape_string($_POST['ProfileComment']) ."',
'active',
'active',
'" . date("Y-m-d") . "',
'" . date("G:i:s") . "')";
mysql_query($query,$connection);
if($auth->id == $prof->id) {
$just_inserted = mysql_insert_id();
$query = "UPDATE `CysticAirwaves` SET `status` = 'dead' WHERE `FromUserID` = '" . $auth->id . "' AND `ToUserID` = '" . $prof->id . "' AND `id` != '" . $just_inserted . "'";
$request = mysql_query($query,$connection);
}
//REPLIES
$query = "INSERT INTO `CysticAirwaves_replies` (
`AirwaveID`,
`FromUserID`,
`comment`,
`status`,
`date`,
`time`
) VALUES (
'" . mysql_real_escape_string($_POST['comment']) . "',
'" . $auth->id . "',
'" . mysql_real_escape_string($_POST['reply']) . "',
'active',
'" . date("Y-m-d") . "',
'" . date("G:i:s") . "'
)";
mysql_query($query,$connection);
$mailto = array();
/* get the person that wrote the inital comment */
$query = "SELECT `FromUserID` FROM `CysticAirwaves` WHERE `id` = '" . mysql_real_escape_string($_POST['comment']) . "' LIMIT 1";
$request = mysql_query($query,$connection);
$result = mysql_fetch_array($request);
$comment_author = new User($result['FromUserID']);
thanks in advance
You can perform a select to see how many entries are in the table already by that user for the current date:
SELECT COUNT(*)
FROM CysticAirwaves
WHERE userid = $auth->id
AND date = CURDATE()
Then only perform the INSERT if the number is below your threshold. Alternatively, you can place a trigger on the INSERT that does this check with every INSERT and bounces the call as well. ("Best practice" would be to place it in the database as this would be a database-related limitation, but that's your call)
It's been a while since I've done MySQL triggers, but I think think is what you're after:
delimeter |
CREATE TRIGGER reply_threshold BEFORE INSERT ON CysticAirwaves_replies
FOR EACH ROW BEGIN
DECLARE reply_count INT;
SET reply_count = (SELECT COUNT(*) FROM CysticAirwaves_replies WHERE userid = NEW.userid AND `date` = CURDATE());
IF reply_count > 5 THEN
SIGNAL SQLSTATE SET MESSAGE_TEXT = 'Too many replies for today';
END IF;
END;
|
delimeter ;
Essentially, if you go to insert a reply in the table and the threshold has been exceeded, a sql error will be raised stopping the action. You can't "prevent" an insert per-say, but you can raise an exception that makes it fall-through.
You can only limit this by the ip address when you don't have a login system. But the ip can change and this is here the problem.
The best way is to secure the form by a login. That only user can post when they are logged in.
Last technique is to use a captcha like Recaptcha then at most time bots fill out your form and spam to your system.
When you have a login. Then make a table related to your usertable and count the INSERTS. Before you INSERT a new comment check the table if there was a INSERT today.
Before to insert the comment, you check if the user has posted more than 5 comments in the day.
If yes, you don't insert the comment and you display a message.
SELECT COUNT(*) FROM CysticAirwaves_replies WHERE FromUserID = the_user_id AND date = CURDATE()
Besides counting before each insertion, you can store the number of comments made by an user somewhere directly, so you don't have to do the count(*) every time (which can be expensive if an user has lots of comments and the table you have is somewhat big).
Like, on commenting:
SELECT comment_count FROM comment_count_table WHERE user_id = ?
If that value is small enough, you do:
UPDATE comment_count_table SET comment_count = comment_count + 1 WHERE user_id = ?
Be careful with this since you'd need to reset that counter somehow.
At my company we implemented this setting a "last modified field". When we do the SELECT, if the "last modified day" is not today, then we reset the counter.
Another option is to have a cron job that resets the counter for all users once every day, but that is way too expensive.
Really stuck on something. I'm trying to update a database and the code looks write - and if I echo it out and paste it directly into phpMyAdmin it works perfectly - but the code itself doesn't work... I have spend a day so far trying to figure out why it's not working and I'm completely out of ideas...
function restoreSession()
{
mysql_connect("theHost", "root", "rootPWD") or die(mysql_error());
mysql_select_db("myDatabase") or die(mysql_error());
$restore_cmd = 'UPDATE wp_dor_cart66_sessions SET user_data = (SELECT user_data FROM wp_dor_cart66_stored_sessions WHERE ip_address = "' . $_SERVER['REMOTE_ADDR'] . '")';
$clean_up = "DELETE FROM `wp_dor_cart66_sessions` WHERE `ip_address` = \"" . $_SERVER['REMOTE_ADDR'] . "\" AND id NOT IN (SELECT id FROM ( SELECT id FROM `wp_dor_cart66_sessions` ORDER BY id DESC LIMIT 1 ) user_data )";
mysql_query($clean_up) or die('Query failed: ' . mysql_error());
$result = mysql_query($restore_cmd) or die('Query failed: ' . mysql_error());
echo "<br/>";
echo $restore_cmd;
echo "<br/>";
var_dump($result);
echo "<br/>";
print_r($result);
}
The resulting output looks like:
UPDATE wp_dor_cart66_sessions SET user_data =
(SELECT user_data FROM wp_dor_cart66_stored_sessions
WHERE ip_address = "196.54.110.24");
bool(true)
1
It doesn't appear to have any errors - but I just can't get it to update. If it didn't work in phpMyAdmin - I'd know there was something wrong with the SQL - but it seems right... I'm just really out of ideas - any help would be greatly appreciated!
Here are the statements again with some formatting:
$restore_cmd = '
UPDATE
wp_dor_cart66_sessions
SET
user_data = (
SELECT
user_data
FROM
wp_dor_cart66_stored_sessions
WHERE
ip_address = "' . $_SERVER['REMOTE_ADDR'] . '"
)
';
$clean_up = "
DELETE FROM
`wp_dor_cart66_sessions`
WHERE
`ip_address` = \"" . $_SERVER['REMOTE_ADDR'] . "\"
AND id NOT IN (
SELECT
id
FROM
(
SELECT
id
FROM
`wp_dor_cart66_sessions`
ORDER BY
id DESC
LIMIT
1
) user_data
)
";
$restore_cmd = 'UPDATE wp_dor_cart66_sessions SET user_data = (SELECT user_data FROM wp_dor_cart66_stored_sessions WHERE ip_address = \"' . $_SERVER['REMOTE_ADDR'] . '\")';
need to escape the quotation marks
Looks like quoting error, Try this:
"UPDATE wp_dor_cart66_sessions SET user_data = (SELECT user_data FROM wp_dor_cart66_stored_sessions WHERE ip_address = '" . $_SERVER['REMOTE_ADDR'] . "')";
If could be that you have multiple results in your SELECT.
What if you do ...
$restore_cmd = 'UPDATE wp_dor_cart66_sessions SET user_data = (SELECT user_data FROM wp_dor_cart66_stored_sessions WHERE ip_address = "' . $_SERVER['REMOTE_ADDR'] . '" LIMIT 1)';
... note the LIMIT 1
Are you sure that the first query is not deleting all the matching rows?
I don't understand the "user_data" part at the end of the first query. But I would check the number of affected rows after each query to see if query is doing any affect on data and if it is, is it doing well or there's just some logical mistake.