I am trying to find a way to insert a value into one of two columns depending on which one is NULL.
$accept_sth = $dbh->prepare("UPDATE user_properties
IF(followup_offer <> NULL, fstatus=?)
ELSE (istatus=?)
WHERE id=?");
$accept_sth->execute($_POST['option'], $_POST['id']);
I am doing it wrong.
No ...brain damage... necessary. You can do it with a query
UPDATE user_properties
SET fstatus = IF(followup_offer IS NULL, fstatus, ?),
istatus = IF(followup_offer IS NULL, ?, istatus)
WHERE id = ?
Note: the only possible drawback for some scenarios of this type of query with conditional SET is that both columns are updated every time (one with a value and one with the old one).
Here is SQLFiddle demo
Related
Hello i am trying to retrieve a list of records from my database and table using two criterias and the data has to be combined as one
the first statement which i have written is
FROM `transactions` WHERE `Start_Date` = '$_POST[start]' AND `Company` = '$_POST[star]' and Status = ''
this statement all the records which has its column as empty,
now i want to also capture together with this data all columns that have status as successful
FROM `transactions` WHERE `Start_Date` = '$_POST[start]' AND `Company` = '$_POST[star]' and Status = 'successful'
please how do i combine this, i initially tried this
FROM transactions WHERE Start_Date = '$_POST[start]' AND Company = '$_POST[star]' and Status = '' and (status = 'successful')
i thought it should work but it dosent seem to work, any help please on the correct way
Each row in your table will be evaluated individually to see if it meets the criteria defined in the WHERE clause. Since you need to check for two possible values in the same column, and one row cannot have two different values for the same column, you'll need to use OR instead of AND.
WHERE
`Start_Date` = '$_POST[start]'
AND `Company` = '$_POST[star]'
AND (`Status` = '' OR `Status` = 'successful')
The effect of this will be like combining your two queries. You'll get all rows that meet the Start_date and Company criteria as well as having either Status = '' or Status = 'successful'.
You can use "IN" operator to achieve this.
FROM 'transactions'
WHERE 'Start_Date' = '$_POST[start]' AND 'Company' = '$_POST[star]' AND
Status IN ('','successful')
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am checking the for the user_id (it is held in a session) - this is working. Then I am running a SELECT query for that user for the database table click_count. I am checking to see if that user has any records within it, ie: $page_count. If not, I want my INSERT statement to run to add that user to the database table along with other data.
The part I do not understand is it seems that my UPDATE query is always running. For example no matter which user I login with my query only updates the only user in the database table. IE: Bob is the only user in the click_count table, if I log in with Pete, Bob's record is being updated.
I have tested the value for $page_count and it equals 0, so my INSERT should be running. I have also tried if ($page_count === 0) {
Does anyone see anything I am missing?
$curPage = $_SERVER['PHP_SELF'];
$clicks = 0;
$setup = 0;
$page_total_count = 0;
var_dump($user_id);
$click_sql = "
SELECT *
FROM click_count
WHERE user_id = ?
AND page_url = ?
";
$click_stmt = $con->prepare($click_sql);
$click_stmt->execute(array($user_id, $curPage));
$click_stmt_rows = $click_stmt->fetchAll(PDO::FETCH_ASSOC);
$page_count = $click_stmt->rowCount();
foreach ($click_stmt_rows as $click_stmt_row) {
$setup_status = $click_stmt_row['setup'];
$page_total_count = $click_stmt_row['page_count'];
}
if ($page_count == 0) {
$click_insert_sql = "
INSERT INTO click_count
(user_id, page_url, page_count, setup)
VALUES(?, ?, ?, ?)
ON DUPLICATE KEY UPDATE page_count=page_count+1;
";
$click_insert_stmt = $con->prepare($click_insert_sql);
$click_insert_stmt->execute(array($user_id, $curPage, 1, $setup));
}
else {
$click_update_sql = "
UPDATE click_count
SET page_count=page_count+1
WHERE user_id = ?
AND page_url = ?
";
$click_update_stmt = $con->prepare($click_update_sql);
$click_update_stmt->execute(array($user_id, $curPage));
}
Table
click_count
CREATE TABLE `click_count` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`page_url` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`page_count` int(11) NOT NULL,
`setup` int(5) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `user_id` (`user_id`),
UNIQUE KEY `page_url` (`page_url`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Since there is only the one user in the table, there is no record "to insert/update", therefore
ON DUPLICATE KEY UPDATE failed you silently.
A regular UPDATE will suffice:
I.e. and as an example:
UPDATE table SET col_x = 0|1 WHERE col_y = ? // (boolean 0-1)
Note:
If ever you wish to increase a column by counting later on, the syntax would be:
UPDATE table SET col_x = col_x + 1 WHERE col_y = ?
In regards to your asking about how you could improve on your code:
#Fred-ii- Thanks. Yes, it is working now how I want, but if there are ways to improve the code I am always willing to try to learn it. I just remembered people in the past saying that I didn't need the update query at all with the duplicate key update. – Paul
You could use named placeholders :name rather than ? since they are easier to keep track of, but this is of course a matter of opinion that I feel is also shared by many and not just myself.
Footnotes/credits:
I would like to also give credit to the following comment:
"If you always fall into update indicates that $page_count is not zero.. Try to echo() it to see maybe.. I would probably first try to add another user into click_count table and then it may become easier to see where it goes wrong.. – johnyTee"
where the OP responded with:
"#Fred-ii- I figured it out. I used johnyTee's advise and tried adding another user to the database manually and it wouldn't let me because of the unique index for the page_url column. I then removed the unique index from it and now it works perfectly. Thanks for the help! – Paul"
from PHP PDO doc http://php.net/manual/en/pdostatement.rowcount.php
PDOStatement::rowCount() returns the number of rows affected by a
DELETE, INSERT, or UPDATE statement.
if you need th number of rows in select you should use somethings like
$sql = "SELECT *
FROM click_count
WHERE user_id = ?
AND page_url = ?
";
$result = $con->prepare($sql);
$result->execute();
$number_of_rows = $result->fetchColumn();
It may be '0' (a string). You can use intval to convert it to an integer.
$page_count = intval( $click_stmt->rowCount() );
http://php.net/manual/en/function.intval.php
For most databases, PDOStatement::rowCount() does not return the number of rows affected by a SELECT statement. Instead, use PDO::query() to issue a SELECT COUNT(*) statement with the same predicates as your intended SELECT statement, then use PDOStatement::fetchColumn() to retrieve the number of rows that will be returned. Your application can then perform the correct action.
try like this:
$sql = "SELECT count(*)
FROM click_count
WHERE user_id = ?
AND page_url = ?
";
if ($res = $conn->query($sql)) {
/* Check the number of rows that match the SELECT statement */
if ($res->fetchColumn() > 0) {
//insert
}else {
//update
}
}
I have a matter in PHP & Mysql Project.
Simply, I have two tables project and project features,
Every project has as specific features.
CREATE TABLE projects (
ID INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name varchar(255) NOT NULL
);
CREATE TABLE projects_features (
projectId INT NOT NULL,
name varchar(255) NOT NULL,
value varchar(255) NOT NULL,
weight INT NOT NULL
);
INSERT INTO projects VALUES (NULL,'project1');
INSERT INTO projects VALUES (NULL,'project2');
INSERT INTO projects_features VALUES (1,'Feature1','Feature1 Value',1);
INSERT INTO projects_features VALUES (2,'Feature2','Feature2 Value',2);
INSERT INTO projects_features VALUES (1,'Feature3','Feature3 Value',3);
INSERT INTO projects_features VALUES (2,'Feature4','Feature4 Value',4);
INSERT INTO projects_features VALUES (1,'Feature5','Feature5 Value',5);
I Get the Project features by:
SELECT * FROM projects_features WHERE projectId = 1 ORDER BY weight ASC;
So the bigger weight will be down and lower weight will be Up.
Now,
In My View I have move up and move down buttons, so I can re-sort project features.
I can firstly select the current item weight then select the upper item weight ,
then type two update queries to exchange the weight between the two rows,
but it's not a professional way , I don't like to use four queries.
I need to do it in one query Instead of four queries.
Can anybody help please ?
Here's how I'd tackle this, assuming I've understood the question.
First, I'd add a featureId column to projects_features, and make (projectId, featureId) the composite primary key. This isn't actually necessary to my solution; it just makes the rest a whole lot easier. For the next part you need to be able to reference individual records in projects_features.
Next, I'd have the Move buttons populate an array in PHP, like
$update_list = array();
$update_list[i] = array(':project_id' => $proj_id,
':feature_id' => $feat_id,
':new_weight' => $weight);
Finally, I'd do the update through a PHP function that encapsulates the UPDATE statements, like this:
function updateWeights($update_array, $dbh)
{
$sql = 'UPDATE project_features
SET weight = :new_weight
WHERE projectId = :project_id
AND featureId = :feature_id'
$stmt = $dbh->prepare($sql);
foreach ($update_array as $update_item)
{
$stmt->execute($update_item);
}
}
Note I'm using PDO here; it could also be done with mysqli, although mysqli doesn't support named bind parameters so the syntax would be slightly different, something like
function updateWeights($update_array, $dbh)
{
$sql = 'UPDATE project_features
SET weight = ?
WHERE projectId = ?
AND featureId = ?'
$stmt = $dbh->prepare($sql);
foreach ($update_array as $update_item)
{
$stmt->bind_param('i', $update_item[':new_weight']);
$stmt->bind_param('i', $update_item[':project_id']);
$stmt->bind_param('i', $update_item[':feature_id']);
$stmt->execute();
}
}
Also note that I haven't actually run this code, and so make no representation that it is free of syntax or other errors.
I hope that helps.
i have an c++ program that sending POST of logs to my server and store it on database, the problem is that the checking of duplicates before insert a new row is not working, i think that the program send the POST very fast and there is no delay between the POSTS to the server so the Mysqli can't handle this, is there any solution from server client? maybe locking rows or something?
$date = date('Y-m-d', time());
$prep_select_qa = 'SELECT * from `logs` WHERE `guid` = ? AND `error_code` = ? AND `date_create` = ?';
$select_qa = $db->prepare($prep_select_qa);
$select_qa->bind_param('sss', $_POST['guid'], $_POST['error_code'], $date);
$select_qa->execute();
$select_qa->store_result();
$num_rows = $select_qa->num_rows;
if($num_rows == 0)
{
$prep_insert_qa = 'INSERT INTO `logs` (`type`, `guid`, `sent_by`, `class_and_method`, `api_method`, `error_code`, `error_text`, `date_create`) VALUES (?,?,?,?,?,?,?,?)';
$insert_qa = $db->prepare($prep_insert_qa);
$insert_qa->bind_param('ssssssss', $new, $_POST['guid'], $_POST['sentBy'], $_POST['classAndMethodName'], $_POST['APImethod'], $_POST['ErrorCode'], $_POST['ErrorText'], $date);
$insert_qa->execute();
$insert_qa->store_result();
}
First, the answer to your question is that you are retrieving all the rows in order to count them. Presumably, this requires reading all the data in the table and returning some of it (unless you have indexes). A faster method is to check the value returned by this query:
SELECT count(*)
FROM `logs`
WHERE `guid` = ? AND `error_code` = ? AND `date_create` = ?';
And an even faster method is not to count but to determine if any row exists:
SELECT EXISTS (SELECT 1
FROM `logs`
WHERE `guid` = ? AND `error_code` = ? AND `date_create` = ?'
)
This will return 1 if the row exists and 0 otherwise. Both of the above queries and your original query will benefit from having an index on guid, error_code, date_create.
In practice, you should follow Marvin's advice and use a unique index. This means the database does the checking via a unique index rather than the application. One very important reason is a race condition. If two users are inserting the same row at the same time, both might execute the if statement, find there are no matching rows in the table, and then insert duplicate rows.
The SELECT scheme must be enclosed in a BEGIN...COMMIT transaction and have FOR UPDATE on it. Otherwise, some other connection can slip in and defeat your check.
Instead, try to do it in a single, atomic, instruction:
Once you have an INDEX that will prevent duplicates...
INSERT IGNORE -- Silently does nothing if it is a dup.
INSERT...ON DUPLICATE KEY UPDATE -- Lets you change something as you try to insert a dup.
Also, the INSERT solutions will be faster (which was your original question).
I have a problem with mysql query. for a cuople days I cannot solve it.
URL params ?a=1&b=2&c=3
Structure:
attr_id
value_id
query:
SELECT DISTINCT `product_id`
FROM `products_attr_val`
WHERE
(`attr_id` = '".$searchqueryArray2[0]."' AND `value_id` = '".$searchqueryArray2[1]."')
OR (`attr_id` = '".$searchqueryArray2[0]."' AND `value_id` = '".$searchqueryArray2[1]."')
but the problem is that if a=12&b=10
and if there is a product with atribute 10 or atribute 12 it shows. I need to show products with a=12 and b=10.
Whats wrong?
Thanks for help.
Sounds like you need to use GROUP BY and HAVING clauses.
SELECT
`product_id`,
COUNT (`primary_key_id`) AS `attr_count` /* primary key field here */
FROM `products_attr_val`
WHERE
(`attr_id` = ? AND `value_id` = ?)
OR (`attr_id` = ? AND `value_id` = ?)
/* additional as necessary
OR (`attr_id` = ? AND `value_id` = ?)
*/
GROUP BY `product_id`
HAVING `attr_count` = ? /* value here should be equal to number of attributes you are checking for */
Make sure you have a unique index across product_id and attr_id for this to work properly (you should already have this since it would not likely make sense for a product to have multiple records with the same attr_id).
You also need to make sure you are escaping your values for use in your SQL if you are not already. I am showing these variables here with ? which, if you we using prepared statments, would be a way you might write this SQL.