I've meet a serious problem with setMaxResult and setFirstResult.
When i'm trying to get result without setMaxResults and setFirstResult, it works OK, all rows returned.
When i'm using offset = 0 and limit=10 , it works good, 10 rows returned.
When i'm using offset = 10 and limit = 10 , it return 5 rows (must be 7)
Another example, i've used offset = 0 , limit = 20 ,it returned 15 rows.But it must be 17 rows.
With offset=0 and limit = 30 , it returned all 17 rows .... Why this query works so bad ? With offset = 0 and limit 20, it should have returned all 17 rows... but not 15..
Code :
$eligibleCircles = $this->getAllCircles($user);
$results = $this->getEntityManager()
->createQuery(
'SELECT
e
FROM
TestBundle:Event e
LEFT JOIN
e.eligibleCircles eligibleCircles
WHERE
(
eligibleCircles in (:eligibleCircles)
OR
e.owner = :user
)
AND
e.eventStatus = :eventStatus
AND
NOT EXISTS (
SELECT
eh
FROM
TestBundle:EventHidden eh
WHERE
eh.user = :user
AND
eh.event = e
)
AND
e.startDate < :currentDate
ORDER BY e.startDate DESC
'
)
->setParameter('eventStatus', 3)
->setParameter('eligibleCircles', $eligibleCircles )
->setParameter('user', $user )
->setParameter('currentDate', new \DateTime('now') )
->setFirstResult($offset)
->setMaxResults($limitNr)
->getResult();
Cerad is correct with regard to the sql-limit not being useful when you have a join in your query.
If you want to paginate while using Doctrine2 there are some helpfull tools for you available.
Have a look at the documentation here:
http://doctrine-orm.readthedocs.org/en/latest/tutorials/pagination.html
You need a bit of extra code, but most of the complex stuff is handled for you.
It will also require 1 or 2 additional queries to find the correct records+data. This may or may not be a problem in your situation.
Related
I tried moving the WHERE clause many times but I'm still having an error. Am I doing the WHERE NOT IN AND WHERE clause wrong? The code is working perfectly fine until I added the WHERE ha_rooms.deleted != 1 clause. I also tried using deleted <> 1 but it still shows the same error
$query2 = $this->db->query("SELECT * FROM ha_rooms
WHERE ha_rooms.deleted != 1 JOIN ha_user_room_merged
WHERE ha_rooms.room_id NOT IN (SELECT ha_user_room_merged.room_id
FROM ha_user_room_merged WHERE ha_user_room_merged.deleted = 0)
group by ha_rooms.room_id");
The error is this
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 'JOIN ha_user_room_merged WHERE ha_rooms.room_id NOT IN (SELECT
ha_user_room_merg' at line 1
If I said frankly, your query is not done properly in anyway but it gives pretty much clear vision of what you are trying to do if you don't have any other logic behind that. So, I would like to suggest you to do google for SQL Syntax, Ordering, use of GROUP BY, WHERE sub-query etc. BTW below is the proper version of your query please check if it's useful for you
SELECT hr.*
FROM ha_rooms hr
JOIN ha_user_room_merged hurm On hurm.room_id = hr.room_id
WHERE hurm.deleted = 0
AND hr.deleted <> 1
Use below codeigniter query. in your join there is no ON
$all_ids = 0;
$this->db->select('group_concat(room_id) as ids');
$this->db->where('deleted', 0);
$ids = $this->db->get('ha_user_room_merged')->row_array();
if($ids) {
$all_ids = explode(',', $ids['ids']);
}
$this->db->where('hr.deleted !=', 1);
$this->db->where_not_in('hr.room_id', $all_ids);
$this->db->join('ha_user_room_merged hrm', 'hrm.room_id = hr.room_id');
$this->db->group_by('hr.room_id');
$this->db->get('ha_rooms hr')->result_array();
Please try..
select * from ha_rooms as a inner join ha_user_room_merged b on a.ha_rooms.id = b.room_id
where b.deleted <> 0
Output
ha_rooms.room_id ha_user_room_merged.room_id deleted
1 1 1
2 2 1
3 3 1
4 4 1
Thanks :)
In trying to pull down some stock data after a certain set of criteria is triggered from a database I am getting a slow response mostly based around using dynamic data. I have forced to go into a while loop to decern calculations. I was wondering if there is a way to roll this up all into one query if possible. The following is a simplified example of the code I'm using, and maybe a possible solution.
The major problem is the query is super slow, and is only going at a rate of about 29 rows per second. (11000 rows takes roughly 6 mins to query.)
$sql_while_0 = "
SELECT
k.*,
y.exchange
FROM stocks k
JOIN symbols y
ON k.id = y.id
WHERE
(
y.exchange = 'NASDAQ CM' OR
y.exchange = 'NASDAQ GM'
)
AND k.t BETWEEN ? AND ?
ORDER BY t ASC
";
$t_test_begin = 20150101;
$t_test_end = 20150110;
$stmt_while_0 = $pdo->prepare($sql_while_0);
$stmt_while_0->execute([$t_test_begin,$t_test_end]);
$affected_rows = $stmt_while_0->rowCount();
echo "<br /> Rows Affected: ".$affected_rows."<br /><br />";
while ($row_while_0 = $stmt_while_0->fetch())
{
$t_0 = $row_while_0['t'];
// FIND t FROM 20 DAYS AGO
$sql_while = "
SELECT t
FROM usa_stocks_daily_bar
WHERE
t < ?
ORDER BY t DESC
LIMIT 20
";
$stmt_while = $pdo->prepare($sql_while);
$stmt_while->execute([$t_0]);
while ($row_while = $stmt_while->fetch())
{
$t_20 = $row_while['t'];
}
// SELECT close_adj from TWO days ago
// FIND t FROM 20 DAYS AGO
$sql_while = "
SELECT close, close_adj
FROM stocks
WHERE
t = ?
AND id = ?
LIMIT 1
";
$stmt_while = $pdo->prepare($sql_while);
$stmt_while->execute([$t_2,$id_0]);
while ($row_while = $stmt_while->fetch())
{
$close_20 = $row_while['close'];
$close_adj_20 = $row_while['close_adj'];
}
}
So you can see where the problem is... I using two while loops. This works, but is insanely slow. I'm sure the solution is something like this:
SELECT
k.*,
y.exchange,
(
SELECT
close AS close_20
FROM stocks k
WHERE
t = (
SELECT z.t
FROM usa_stocks_daily_bar z
WHERE
t < k.t
ORDER BY z.t DESC
LIMIT 1 OFFSET 19
)
AND id = k.id
LIMIT 1
)
FROM stocks k
JOIN symbols y
ON k.id = y.id
WHERE
(
y.exchange = 'NASDAQ CM' OR
y.exchange = 'NASDAQ GM'
)
AND k.t BETWEEN 20150101 AND 20150102
ORDER BY t ASC
LIMIT 2
So you can see from the second query is what I want to accomplish. I tried this before and got an error saying that the subquery pulled more than one row (as you can see from the limit 20, to get 20 days ago). The table usa_stocks_daily_bar is simply a table with the dates listed -> 20150101,20150102,...
Edit:
Fuzzy recommended the 2nd tier of code, and it is able to be entered, but freezes up in MySQL for some reason.
Is this because you cannot do two or more layers of subqueries?
Thanks for your help.
Just quickly, you seem to have one too many "OR"
WHERE
(
y.exchange = 'NASDAQ CM' OR
y.exchange = 'NASDAQ GM' OR
)
AND k.t BETWEEN 20150101 AND 20150110
Should be ...
WHERE
(
y.exchange = 'NASDAQ CM' OR
y.exchange = 'NASDAQ GM'
)
AND k.t BETWEEN 20150101 AND 20150110
I have a series of queries that find out what is the best position every user had over a series of events (note: all users have the same $points_pos, so I am looking at a discriminating value). The query is looped for every user.
$max=$amount+1;
$i=1;
$highestsofar="99";
$numpointsall = "SELECT driver, position FROM standings_drivers WHERE season='42' AND points='$points_pos'";
$numall = mysql_query($numpointsall);
while ($i<$max) {
while ($row = mysql_fetch_row($numall)) {
$driver_id = $row[0];
$posvar = "SELECT position FROM results WHERE compId='$compId' AND driverId='$driver_id' AND eventID>='$firstevent' AND eventID<='$lastevent' AND (eventSession!='T' AND eventSession!='P' AND eventSession!='Q' AND eventSession!='Q1' AND eventSession!='Q2' AND eventSession!='QA') ORDER BY position ASC LIMIT 1";
$posres = mysql_query($posvar);
while ($row = mysql_fetch_row($posres)) {
$highestpos = $row[0];
}
$i++;
}
}
Having established the $highestpos for each of the $driver_id, how can I arrange them in order of best position (that is, the ones with the lowest $highestpos)?
Ideally, I want to achieve something that tells me:
$driver_id = 1
$driver_id = 2 etc
so that I can amend a table by putting them in the correct order of position.
EDIT: additional info
The results table look like this:
ID compId eventId eventSession driverId position
1 2 739 R 563 7
2 2 739 R 903 1
3 2 562 R 874 16
...
In the case above, assuming that 739 and 562 are the IDs of events in the range, I would like to order the three users in driverId as follows:
903 = 1st
563 = 2nd
874 = 3rd
Thank you for your help!
One thing about SQL is that it's typically much better than you (or I) are at getting data. The developers and architects for Microsoft, Oracle, etc. have spent a great deal of time and effort working on the best ways to select data, so trying to duplicate their efforts (like looping over results and getting values, etc.) is usually a mistake.
All of your code can likely be replaced with a single SQL query:
SELECT
SD.driver,
MIN(R.position) AS highest_position
FROM
Standings_Drivers SD
INNER JOIN Results R ON
R.driver = SD.driver AND
R.compId = ? AND
eventID >= ? AND
eventID <= ? AND
eventSession NOT IN ('T', 'P', 'Q', 'Q1', 'Q2', 'QA')
WHERE
SD.season = '42' AND -- Should this really be a string and not an integer?
SD.points = ?
GROUP BY
SD.driver
ORDER BY
MIN(R.position)
The question marks are where you would pass in your various parameters. Make sure that you're are executing this as a parameterized query and not just building up a complete string. I don't program in PHP, so I don't know the syntax for that. Googling for "sql injection php" should help you out there though.
php
$wall_id = 5;
$pull_adj_id = $connectDB->prepare("(SELECT walls.wall_id FROM walls WHERE
walls.wall_id > ? ORDER BY walls.wall_id ASC LIMIT 1)
UNION
(SELECT walls.wall_id FROM walls WHERE
walls.wall_id < ? ORDER BY walls.wall_id DESC LIMIT 1);");
$pull_adj_ids->bind_param('ii', $wall_id, $wall_id);
$pull_adj_ids->execute();
$adj_result = $pull_adj_ids->get_result();
$adj_data = $adj_result->fetch_array();
print_r($adj_data);
Ouput: Array ( [0] => 5 [wall_id] => 5 )
In relation to my previous question, I trying to build my query to pull both the greater than and less than ids from the table but the query is return only one value. But when I try to run the very same query in phpMyAdmin it gives 6 and 4.
Your query returns 2 rows while you are fetching only one
you have to loop your results.
try this
$pull_adj_ids->execute();
$pull_adj_ids->store_result();
$adj_result = $pull_adj_ids->bind_result($wall_id);
while ($adj_data = $adj_result->fetch()){
echo $wall_id.'<br />';
}
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.