So i have a Joomla site and in the joomla documentation I can't find anything to do with MySQL's IF, ELSE function within a query.
The part of the query i need a if statement in MySQL is here.
$query->where($db->quoteName('container').' != 1');
It should be doing something like this :
$query->where('IF '.$db->quoteName('server_number').' != '.$number.' THEN '$query->where($db->quoteName('container').' != 1');' END');
If the $number input does not match with the server_number column data then to add a where statement to the mysql query.
Full MySQL Query :
SELECT a.*,ext.media_type
FROM database_hwdms_processes AS a
LEFT JOIN database_hwdms_media AS media ON media.id = a.media_id
LEFT JOIN database_hwdms_ext AS ext ON ext.id = media.ext_id
WHERE (a.status = 1 || a.status = 3) AND a.attempts < 5 AND `container` != 1 AND
server = 1
ORDER BY a.media_id ASC
Want to add a "IF server_number != 1 THEN WHERE container != 1 END" would mean replacing "AND container != 1"
I figured out a better way to resolve my problem using MySQL's
OR ||
function
So my fixed code became this :
PHP :
$query->where('('.$db->quoteName('server_number').' = '.$number.' || '.$db->quoteName('container').' != 1 )');
In plain MySQL text :
SELECT a.*,ext.media_type
FROM database_hwdms_processes AS a
LEFT JOIN database_hwdms_media AS media ON media.id = a.media_id
LEFT JOIN database_hwdms_ext AS ext ON ext.id = media.ext_id
WHERE (a.status = 1 || a.status = 3) AND a.attempts < 5 AND ( `server_number` = 1 || `container` != 1 )AND
server = 1
ORDER BY a.media_id ASC
Related
I have the following SQL:
UPDATE msh_leads ml
LEFT JOIN msh_leads_disposition_log dl
ON ml.id = dl.lead_id
SET ml.assigned_to = null
WHERE ((dl.disposition_id != 6 AND dl.disposition_id != 3) OR (dl.disposition_id IS NULL))
AND (ml.assigned_to = ? AND ml.decline = 0 AND ml.subcategory_id = ?)
There is a bit of logic in creating this (some of the where's come and go depending on certain situations) so I was hoping to recreate this in Codeigniter (2.2) Active Record. Im not sure how to add a join to an update or how to add multiple complex where statements to an update.
This'll help you. Try this.
Note: you need to place your values over ? else it'll throw an error 1064
$this->db->set('ml.assigned_to', 'null');
$this->db->where('ml.assigned_to = ?');
$this->db->where('((dl.disposition_id != 6 AND dl.disposition_id != 3) OR (dl.disposition_id IS NULL))');
$this->db->where('ml.decline = 0');
$this->db->where('ml.subcategory_id = ?');
$this->db->update('msh_leads ml join msh_leads_disposition_log dl on ml.id = dl.lead_id');
I'm trying to use the CASE WHEN statement, but it doesn't seem to work. Is there any change that I can make to this in order to make it work, or is it completely wrong?
"CASE
WHEN (a != '1' AND b != '1' AND c != '1' AND d != '1' AND e != '1') WHERE id = :id
THEN UPDATE table SET f = 0 WHERE f = 1
WHEN (a != '1' AND b != '1' AND c != '1' AND d != '1' AND e != '1') WHERE id = :id
THEN UPDATE table SET f = 1 WHERE id = :id
ELSE f
END"
I really can't figure this out, and I have tried looking for an answer in different places, but I can't find something similar. Thanks.
Edit:
This is not part of a SELECT statement. I have six columns and one unique id for each row. What I want, is that each row only have one of its columns set to 1, at a time. If a row has already one column set to 1, then you can't set another of its columns to 1. Also, if one column is already set to one in one row, then the same column can't be set to 1 in another row. So I guess that I want it to be mutually exclusive, both vertically and horizontally, hence why both WHEN statements are the same, the first one so that all previous rows that had a 1 in that column will be reseted to 0, before assigning the 1 to the specific chosen column (by id). I placed a WHERE inside the CASE statement because I thought you could do that, judging by the comments, I guess not.
That's the full query, I am using prepared statements, and before that, I had this:
$q = $con->query("UPDATE table SET f=0 WHERE f=1");
$q = $con->prepare("UPDATE table SET f=1 WHERE id = :id");
$q->execute(array('id' => "$id"));
I'm really a beginner with MySQL, so maybe my solution is laughable, and I'm sorry for that. I hope I could explain clearly what I want to do. I don't know where to find the error log, but after posting this, I'm looking for it, and will add a further update. So far I can tell you that I don't know if there's an error (but I'm pretty sure there is, judging by the replies), but what I can tell you is that upon executing the query, it does nothing.
Edit2:
Here's the error that I get when using the query that I posted:
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CASE WHEN ...'
I'm trying other solutions...
Edit3:
Hello, I've managed to find a way to do what I was trying to do. I couldn't do it using only the CASE THEN syntax, and in fact I had to write a whole lot of new code (and queries), so I'm guessing that what I did is NOT the simplest way (and definitely not that fast), and I'm pretty sure it's doable with just one query, if so, the answer is appreciated, and I'm thankful with all of you who tried to help! Apparently I didn't explain myself well. I tried the code you all suggested, and it all works (there's one exception with someone's code, which I'll clarify), but it doesn't serve my purpose. Anyway, here's what I did:
$q = $con->prepare("SELECT id FROM table WHERE f = 1"); //Find the id of the row that has already f = 1
$q->bindColumn(1, $prev_id); //store as $prev_id, it might be useful later
$q->execute();
$q->fetch();
$q = $con->query("UPDATE table SET f = 0 WHERE f = 1"); //Reset row to f = 0
$q = $con->prepare("
UPDATE table
SET f = CASE WHEN (a != '1' AND b != '1' AND c != '1' AND d != '1' AND e != '1')
THEN '1'
ELSE f //The original query, IF
END //selected row != 1 on every other
WHERE id = :id //column, then f = 1 on selected id
"); //else, keep previous state (f = 0)
$q->execute(array('id' => "$id"));
$q = $con->prepare("SELECT f FROM table WHERE id = :id");
$q->bindColumn(1, $last_value);
$q->execute(array('id' => "$id")); //Get value of f on last modified id (from previous
$q->fetch(); //query) and store it
if($last_value == 0) //if f = 0, it means the selected id was not modified.
{ //Then, restore f = 1 on the row that previously had it
$q = $con->prepare("UPDATE table SET f = 1 WHERE id = :prev_id");
$q->execute(array('prev_id' => $prev_id));
}
Anyway, thanks to you all, I've learnt a lot today, and it's been fun. Still, I guess this is NOT the best way to do this, and if anyone comes up with a better answer, I'll appreciate it!
please check below:
UPDATE table
SET f =
CASE
WHEN (a != '1' AND b != '1' AND c != '1' AND d != '1' AND e != '1') THEN
0
WHEN (a != '1' AND b != '1' AND c != '1' AND d != '1' AND e != '1') THEN
1
ELSE f
END
WHERE ID = :id
But here both the WHEN clause condition are same.
this should work:
UPDATE table
SET f =
CASE
WHEN (a != '1' AND b != '1' AND c != '1' AND d != '1' AND e != '1' AND f = '1') THEN
0
WHEN (a != '1' AND b != '1' AND c != '1' AND d != '1' AND e != '1') THEN
1
ELSE f
END
WHERE ID = :id
The first When clause takes in account the OP's need to set f to 0 when f = 1.
It seems that you don't need an update when a, b, c, d, and e are not equal to 1. In which case, you can use a where clause on your update (and remove the WHERE from your CASE statement):
UPDATE table
SET f =
CASE
WHEN f = 1 THEN 0
ELSE 1
END
WHERE a != '1' AND b != '1' AND c != '1' AND d != '1' AND e != '1'
AND ID = :id;
There's no sense updating f to equal f, as there's no change.
Also, typically a CASE statement follows this format:
CASE
WHEN condition THEN result
WHEN condition THEN result
ELSE default_value
END
See http://dev.mysql.com/doc/refman/5.0/en/case.html (MySQL) and http://www.postgresql.org/docs/9.2/static/functions-conditional.html (PostgreSQL).
I have this MySQL query which I am loading in to my home controller and after running Codeigniter's $this->output->enable_profiler(TRUE); I get an execution time of 5.3044
The Query inside my model:
class Post extends CI_Model {
function stream($uid, $updated, $limit) {
$now = microtime(true);
$sql = "
SELECT
*
FROM
vPAS_Posts_Users_Temp
WHERE
post_user_id = ?
AND post_type !=4
AND post_updated > ?
AND post_updated < ?
UNION
SELECT
u.*
FROM
vPAS_Posts_Users_Temp u
JOIN
PAS_Follow f
ON f.folw_followed_user_id = u.post_dynamic_pid
WHERE u.post_updated > ?
AND post_updated < ?
AND (( f.folw_follower_user_id = ? AND f.folw_deleted = 0 )
OR ( u.post_passed_on_by = f.folw_follower_user_id OR u.post_passed_on_by = ? AND u.post_user_id != ? AND u.post_type =4 ))
ORDER BY
post_posted_date DESC
LIMIT ?
";
$query = $this->db->query($sql, array($uid, $updated, $now, $updated, $now, $uid, $uid, $uid, $limit));
return $query->result();
}
}
Is there anything I can do here to improve the execution time and therefore increase my page load?
Edit
Explain Results
MySQL Workbench Visual Explain
Maybe you won't believe it, but DON'T retrieve SELECT * in your SQL. Just write the fields you want to retrieve and I think it'll speed up a lot.
I've seen increases in speed of more than 20 times when executing a query (from 0.4secs to 0.02 secs) just changing * for required fields.
Other thing: If you have an auto_increment id on INSERT in your tables, DON'T use post_posted_date as ORDER field. Ordering by DATETIME fields is slow, and if you may use an INT id (which hopefully you will have as an index) you will achieve the same result quicker.
UPDATE
As required in the question, technical reasons:
For not using SELECT *: Which is faster/best? SELECT * or SELECT column1, colum2, column3, etc. This is for SQL, but for MySQL (not as complete as question before) mySQL Query - Selecting Fields
For Ordering by Datetime: SQL, SQL Server 2008: Ordering by datetime is too slow, and again, related to MySQL: MySQL performance optimization: order by datetime field
Bonus: Learning how to set the indexes: http://ronaldbradford.com/blog/tag/covering-index/
I would add indexes on post_user_id, post_updated and folw_follower_user_id.
In this case it may also be better to not use union and separate the query into two separate ones and then use PHP to combine to two result sets.
If you switched to using active record you could also look into caching, to get better performance
The rows column shows an estimate for how many rows needs to be examined, which as I understand, means that in your case, it has to scan 72 * 1 * 2627 * 1 * 2 rows, which is quite a lot.
Now, the trick is to bring down this number, and one way is to add indexes. In your case, I would suggest adding an index which contains:
post_user_id, post_type, post_updated, post_updated.
This should bring down the first result set, of 72 rows.
Now for the UNION, try using UNION ALL instead, as it is claimed to be faster.
If that doesn't fix the problem, I would suggest rewriting the query to not use a UNION call at all.
Try the query with left join as you are trying to union on same table
"SELECT
u.*
FROM
vPAS_Posts_Users_Temp u
LEFT JOIN PAS_Follow f ON f.folw_followed_user_id = u.post_dynamic_pid
WHERE (
u.post_user_id = ?
AND u.post_type !=4
AND u.post_updated > ?
AND u.post_updated < ?
)
OR
(
u.post_updated > ?
AND post_updated < ?
AND (( f.folw_follower_user_id = ? AND f.folw_deleted = 0 )
OR ( u.post_passed_on_by = f.folw_follower_user_id OR u.post_passed_on_by = ? AND u.post_user_id != ? AND u.post_type =4 ))
)
ORDER BY
u.post_posted_date DESC
LIMIT ?"
I think you can remove the UNION from the query and make use of left join instead and avoid the unnecessary conditions:
SELECT U.*
FROM vPAS_Posts_Users_Temp AS U
LEFT JOIN PAS_Follow AS F ON F.folw_followed_user_id = U.post_dynamic_pid
WHERE U.post_updated > ?
AND U.post_updated < ?
AND (
(
F.folw_follower_user_id = ? AND F.folw_deleted = 0
)
OR
(
U.post_passed_on_by = F.folw_follower_user_id OR U.post_passed_on_by = ?
)
)
ORDER BY
U.post_posted_date DESC
LIMIT ?
Also identify and set proper indexes in your tables.
I have updated an old system and I have a query problem.
To get to business this is the direct problem:
There are new records witch are associated with an id to other records. There are also old records which are not.
Case1 : there is a INT id and when that is present the query has to use AND after an include.
Case 2 : when the value of the INT id is 0 it has to do nothing
This is the part of the query where I need to make an variable AND statement:
LEFT JOIN table v ON v.producten_id = i.producten_id AND v.t5_id = i.t5_id AND i.id = v.inkoop_id
I never used IF stamens inside a query but i am looking for something like this:
LEFT JOIN table v ON v.producten_id = i.producten_id AND v.t5_id = i.t5_id if(v.inkoop_id > 0){AND i.id = v.inkoop_id}
Try this:
LEFT JOIN table v
ON v.producten_id = i.producten_id
AND v.t5_id = i.t5_id
AND (v.inkoop_id <= 0 OR i.id = v.inkoop_id)
How about this....
LEFT JOIN table v ON v.producten_id = i.producten_id
AND v.t5_id = i.t5_id
AND ((v.inkoop_id > 0 AND i.id = v.inkoop_id) OR (v.inkoop_id = 0))
I am trying to create a SQL query that will select everything shown...but I have a condition where the total hours !=0. This works but I must add one more condition that would exclude the condition of total hours !=0.
I basically need the query to look like: AND project_timecard_task_days.total_hours != 0 UNLESS task.type ="Fixed Rate"
So, the "unless" part of the statement is the issue. Any help will be much appreciated!
SELECT project_timecard_tasks.task_id,
project_timecard_tasks.datetime,
project_timecard_tasks.total_hours,
project_timecard_tasks.user_id,
project_timecard_tasks.project_id,
users.user_id,
users.firstname,
users.lastname,
users.billingrate,
tasks.id,
tasks.taskname,
tasks.billingoption,
tasks.fixedrate,
tasks.rate_schedule_id,
hourlyrates.rate_schedule_id,
hourlyrates.hourlyrate,
project_timecard_tasks.project_task_id,
project_timecard_task_days.project_task_id,
project_timecard_task_days.project_task_day_id,
project_timecard_task_days.total_hours,
project_timecard_task_days.comments,
project_timecard_task_days.invoiced
FROM project_timecard_tasks
JOIN users
ON project_timecard_tasks.user_id = users.user_id
JOIN tasks
ON project_timecard_tasks.task_id = tasks.id
JOIN project_timecard_task_days
ON project_timecard_tasks.project_task_id =
project_timecard_task_days.project_task_id
JOIN hourlyrates
ON project_timecard_tasks.billing_code_id = hourlyrates.hourly_rate_id
WHERE project_timecard_tasks.project_id = '$jobNumber'
AND project_timecard_task_days.total_hours != 0
AND project_timecard_task_days.invoiced != 1
...AND (project_timecard_task_days.total_hours != 0 OR task.type ="Fixed Rate")...
Just use OR:
WHERE
(
project_timecard_tasks.project_id = '$jobNumber'
AND
project_timecard_task_days.total_hours != 0
AND
project_timecard_task_days.invoiced != 1
)
OR
task.type ="Fixed Rate"
or perhaps (depending on how you want your conditions):
WHERE
project_timecard_tasks.project_id = '$jobNumber'
AND
project_timecard_task_days.invoiced != 1
AND
(
project_timecard_task_days.total_hours != 0
OR
task.type ="Fixed Rate"
)
Use an OR statement.
...
AND (project_timecard_task_days.total_hours != 0 OR task.type = "Fixed Rate")
AND...