codeigniter pagination after union - mysql

I have a script that makes a union with different tables of my database.
I need to show the result with pagination to make it more readable to the user.
This is my code:
//Fetch
foreach($query_info->result() as $info){
//I'm going to create a query for each row i get from the db
$query [] = (' (
SELECT
'.$info->slug.'_dog.`name`,
`age`,
'.$info->slug.'_breed.`name` as breed,
`sex`,
`link`,
`sterilized`,
\''.$info->slug.'\' as prefix
FROM
'.$info->slug.'_dog,
'.$info->slug.'_breed
WHERE
'.$info->slug.'_dog.breed = '.$info->slug.'_breed.id
AND
'.$info->slug.'_dog.type = '.$type.'
)';
}
//implode different UNION
$query_final = implode(" UNION ",$query);
As you can see the the query could be very big.
How can I paginate?
My second option is make a full View with all the result of the tables, about 10-20 tables...
Which is faster for the database? the "big" UNION or a View?

I don't know which is faster, but to do the UNION, you can add an offset and limit to the end of the total query for your pagination. In only the first query, you can add SQL_CALC_FOUND_ROWS in the select. Something like this: (Note that there is no comma after SQL_CALC_FOUND_ROWS)
(SELECT SQL_CALC_FOUND_ROWS column1, column2 FROM etc...) UNION (SELECT column1, column2 FROM etc...) LIMIT 0,10
After you have ran the query, immediately run this query:
SELECT FOUND_ROWS();
It will return the total records like there was no LIMIT on your query. So basically you do not have to run the query again to count the results.
For creating the rest of the pagination, you can use CI it's own pagination library:
http://codeigniter.com/user_guide/libraries/pagination.html
// Edit:
For returning data from the model, you could use something like this:
$results['data'] = $this->db->query($sql)->result_array();
$total = $this->db->query('SELECT FOUND_ROWS() as total')->row_array();
$results['total'] = $total['total'];
return $results;
It can probably be optimized a bit more.

Related

Can a mysql query be extended as child of another query?

Lets assume we have got query1 as follow :
select * from users where status = 1
this will output some results,I can cache these data, now the second query is :
select * from users where status = 1 and point >= 50
as you see the second query is somehow the child of first query, it returns a subset of last query data and has common code as well, is there a way which I can speed up my second query by using first query results and shorten my code using the first query code?
Yes, you use nested queries:
select x.*
from
(
select * from users
where status = 1
) as x
where x.point >= 50;

MySql Select columns from same table based on different condition

I have to run multiple selects on a table for and get resultset for 2 columns. One solution i found is by using UNION as below.
SELECT cap_id, cap_code FROM cap_master
where cap_type = 'Type1' and cap_desc = 'CapDesc1'
UNION
SELECT cap_id, cap_code FROM cap_master
where cap_type = 'Type2' and cap_desc = 'CapDesc2'
Is there any other way to do this. There could be some 10-20 select statements in one go. Will this affect performance, if so what would be a better approach.
I think you should just be able to use one query with a larger WHERE clause using OR statements.
Example
SELECT cap_id, cap_code
FROM cap_master
WHERE (cap_type = 'Type1' AND cap_desc = 'CapDesc1`)
OR (cap_type = 'Type2' AND cap_desc = 'CapDesc2')
That is a least a starting point for getting results for only when the cap_type and cap_desc are specific values.

Why is this SQL query with subquery very slow?

I have this query:
select *
from transaction_batch
where id IN
(
select MAX(id) as id
from transaction_batch
where status_id IN (1,2)
group by status_id
);
The inner query runs very fast (less than 0.1 seconds) to get two ID's, one for status 1, one for status 2, then it selects based on primary key so it is indexed. The explain query says that it's searching 135k rows using where only, and I cannot for the life of me figure out why this is so slow.
The inner query is run seperatly for every row of your table over and over again.
As there is no reference to the outer query in the inner query, I suggest you split those two queries and just insert the results of the inner query in the WHERE clause.
select b.*
from transaction_batch b
inner join (
select max(id) as id
from transaction_batch
where status_id in (1, 2)
group by status_id
) bm on b.id = bm.id
my first post here.. sorry about the lack of formatting
I had a performance problem shown below:
90sec: WHERE [Column] LIKE (Select [Value] From [Table]) //Dynamic, slow
1sec: WHERE [Column] LIKE ('A','B','C') //Hardcoded, fast
1sec: WHERE #CSV like CONCAT('%',[Column],'%') //Solution, below
I had tried joining rather than subquerying.
I had also tried a hardcoded CTE.
I had lastly tried a temp table.
None of these standard options worked, and I was not willing to dosp_execute option.
The only solution that worked as:
DECLARE #CSV nvarchar(max) = Select STRING_AGG([Value],',') From [Table];
// This yields #CSV = 'A,B,C'
...
WHERE #CSV LIKE CONCAT('%',[Column],'%')

Help with complex mysql query

I have an existing mysql query that I need to add to and I'm not sure how to go about it.
Here is my current sql query.
SELECT tbl_brokerage_names.brokerage_id, tbl_brokerage_names.short_name,
b.indication, b.max_indication
FROM tbl_brokerage_names
LEFT JOIN (
SELECT * FROM tbl_recommendation_brokerages
WHERE recommendation_id = {$_GET['id']}
) b ON (tbl_brokerage_names.brokerage_id = b.brokerage_id)
ORDER BY tbl_brokerage_names.short_name ASC
Here is the query that I need to work into the previous query.
SELECT * , COUNT( * )
FROM tbl_streetaccounts
JOIN tbl_brokerage_names
WHERE tbl_brokerage_names.brokerage_id = tbl_streetaccounts.brokerage_id
Basically I need to return a count, so I need to combine these two queries.
You should run these as two separate queries.
The COUNT(*) query will return a single row, so there's no way to "combine" it with the first query while preserving the multi-row result of the first query.
Also, when you SELECT *, COUNT(*) you will get columns from some arbitrary row.
By the way, you have a glaring SQL injection vulnerability. Don't interpolate $_GET parameters directly in your SQL query. Instead, coerce it to an integer:
<?php
$id = (int) $_GET['id'];
$sql = "SELECT ... WHERE recommendation_id = {$id}";
Like #Bill said, you cannot get the count in every row without really weird syntax, but you can get an overall count using GROUP BY ... WITH ROLLUP.
e.g.:
<?php
$id = mysql_real_escape_string($_GET['id']); //works with anything, not just numbers
$query = "
SELECT tbl_brokerage_names.brokerage_id
, tbl_brokerage_names.short_name
, b.indication
, b.max_indication
, count(*) as rowcount
FROM tbl_brokerage_names
LEFT JOIN (
SELECT * FROM tbl_recommendation_brokerages
WHERE recommendation_id = '$id' //The single quotes are essential for safety!
) b ON (tbl_brokerage_names.brokerage_id = b.brokerage_id)
GROUP BY tbl_brokerage_names.brokerage_id WITH ROLLUP
ORDER BY tbl_brokerage_names.short_name ASC
";
The GROUP BY .. WITH ROLLUP will add an extra line to the result with all NULL's for the non aggregated columns and a grand total count.
If you have any lines where rowcount > 0 then you need to add extra clauses from table b to the group by clause to prevent MySQL from hiding arbitrary rows.
Table tbl_brokerage_names is already fully defined because you are grouping by the primary key.

How to get random rows in inner join using mysql?

I am using following queries to fetch random rows,
'SELECT * FROM TABLENAME1 ORDER BY RAND() LIMIT 1' . this query will return random rows.But i need to get the name which is placed in another table.so here i have to use join queries.
'SELECT tablename1.*,tablename2.name FROM tablename1 INNER JOIN tablename2 ON tablename1.id = tablename2.id ORDER BY RAND(tablename1.id)'
The above queries return same rows everytime, I am not getting random rows.Kindly help me on this.
RAND(tablename1.id) uses tablename1.id as the seed for the pseudorandom number generator, so it will give you the same result every time. Try just using RAND() in your second query.
For some reason, you're seeding the 2nd version of the query with tablename1.id.
Calls to RAND() with the same seed value return the same results.