PHP vs Phpmyadmin - php

I've got this code which i execute on phpmyadmin which works 100%
Create Temporary Table Searches ( id int, dt datetime);
Create Temporary Table Searches1 ( id int, dt datetime, count int);
insert into Searches(id, dt) select a.id, now() from tblSavedSearches a;
insert into Searches1(id, dt, count)
select
b.savedSearchesId,
(select c.dt from tblSavedSearchesDetails c where b.savedSearchesId = c.savedSearchesId order by c.dt desc limit 1) as 'dt',
count(b.savedSearchesId) as 'cnt'
from tblSavedSearchesDetails b
group by b.savedSearchesId;
insert into tblSavedSearchResults(savedSearchId,DtSearched,isEnabled)
select id,now(),0 from Searches where not id in (select savedSearchId from tblSavedSearchResults);
update tblSavedSearchResults
inner join Searches1 on tblSavedSearchResults.savedSearchId = Searches1.id
Set tblSavedSearchResults.DtSearched = Searches1.dt, tblSavedSearchResults.isEnabled = 1;
However when i put the same code in php as below it generates an error
$dba = DbConnect::CreateDbaInstance();
$query = "";
$query.="Create Temporary Table Searches ( id int, dt datetime); ";
$query.="Create Temporary Table Searches1 ( id int, dt datetime, count int); ";
$query.="insert into Searches(id, dt) select a.id, now() from tblSavedSearches a; ";
$query.="insert into Searches1(id, dt, count) ";
$query.="select ";
$query.=" b.savedSearchesId, ";
$query.=" (select c.dt from tblSavedSearchesDetails c where b.savedSearchesId = c.savedSearchesId order by c.dt desc limit 1) as 'dt', ";
$query.=" count(b.savedSearchesId) as 'cnt' ";
$query.="from tblSavedSearchesDetails b ";
$query.="group by b.savedSearchesId; ";
$query.="insert into tblSavedSearchResults(savedSearchId,DtSearched,isEnabled) ";
$query.="select id,now(),0 from Searches where not id in (select savedSearchId from tblSavedSearchResults); ";
$query.="update tblSavedSearchResults ";
$query.="inner join Searches1 on tblSavedSearchResults.savedSearchId = Searches1.id ";
$query.="Set tblSavedSearchResults.DtSearched = Searches1.dt, tblSavedSearchResults.isEnabled = 1; ";
$dba->DbQuery($query) or die(mysql_error());
I get the following error
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 'Create Temporary Table Searches1 ( id int, dt datetime, count int) insert into S' at line 1
Please if someone could assist me with this ...
Thanks

If your $dba->DbQuery($query) method is actually using mysql_query (Which I suppose it does, as you are using mysql_error), then, you cannot execute more than one query per call (quoting) :
mysql_query() sends a unique query (multiple queries are not supported) to the currently active
database on the server that's
associated with the specified
link_identifier.
You'll have to either :
separate your queries, and call mysql_query once for each query
should be quite easy, here : instead of concatening all queries into $query, just execute them one by one.
or stop using mysql_*, and start working with MySQLi, which provides a mysqli_multi_query function

You can only execute queries one at a time via PHP. Call $dba->DbQuery() once per new query instead.

Related

MySQL Union query taking too much time to execute

I'm trying to get a single MySQL query result from different queries working on different table and databases, this is my table structure with database names:
database ads1-
tables: clicks_214,requests
database ads2-
tables: clicks_255,requests
database ads3- tables: clicks_256,requests
and this is the query which I'm trying to execute
$query="";
for($i=1;$i<4;++$i)
{
$this->db_num=$i;
$this->selectDB($i);
$table=$this->getTableName();
$db=$this->getDatabaseName();
$query.="(SELECT r.kwd, count(c.rid) as cnum, count(r.kwd) as rnum
FROM $db.requests r LEFT JOIN $db.$table c ON r.id=c.rid
WHERE hid='$hid'
AND r.time BETWEEN '$date1 $hour1:00:00' AND '$date2 $hour2:59:59'
GROUP BY r.kwd
ORDER BY cnum DESC
LIMIT $limit,50)";
if($i<3)
{
$query.=" UNION ";
}
}
I'm certainly sure that this isn't the best way to do it, just because I have to wait about 5 minutes to get results. Is there any way to do this much faster? I've already set indexes on all of the 3 DBs
this is an EXPLAIN result:
a) You SHOULD NOT make such crossdatabase queries. With your DB structure it would be more appropriate to run 3 independent queries and combine the result using some simple script Or to make a temporary table in one of the databases where you can combine data from every one of those
b) On large databases put some indexes to improve the speed. It is not the solution though...
You can try to play with Temp tables:
$this->selectDB('temptableDB');
$maketemp = "
CREATE TEMPORARY TABLE temp_table_1 (
`kwd` int ,
`rid` int,
)
";
mysql_query($maketemp, $connection) or die ("Sql error : ".mysql_error());
for($i=1;$i<4;++$i)
{
$this->db_num=$i;
$this->selectDB($i);
$table=$this->getTableName();
$db=$this->getDatabaseName();
$inserttemp = "
INSERT INTO temptableDB.temp_table_1
(`kwd`, `rid`)
SELECT r.kwd, c.rid
FROM $db.requests r LEFT JOIN $db.$table c ON r.id=c.rid
WHERE hid='$hid'
AND r.time BETWEEN '$date1 $hour1:00:00' AND '$date2 $hour2:59:59'
";
mysql_query($inserttemp, $connection) or die ("Sql error : ".mysql_error());
}
$select = "
SELECT kwd, count(rid) as cnum, count(kwd) as rnum
FROM temp_table_1
GROUP BY r.kwd
ORDER BY cnum DESC
";
$export = mysql_query($select, $connection) or die ("Sql error : ".mysql_error());

SQL query with join shows only one result

I have sql query which should shows all records from table swt_modules, but it shows only first row.
$query1 = mysql_query ("SELECT swt_modules.id, swt_modules.name, swt_exam_regs.name AS exam_regs
FROM `swt_modules`
JOIN `swt_exam_regs`
USING ( `id` )
WHERE swt_exam_regs.id = swt_modules.exam_regulation
ORDER BY swt_modules.name DESC , swt_modules.id DESC
LIMIT " . $limit . "");
while ($fetch1 = mysql_fetch_array ($query1))
{
...
}
I have in this table (swt_modules) 3 rows and in each of them value of field "exam_regulation" is 1. In table swt_exam_regs I have only 1 row with 2 columns - id and name. Swt_modules.id stores id number. Which join I should use to be able to see all records?
I would also suggest using mysqli or pdo instead of the now deprecated mysql.
$query1 = mysql_query ("
SELECT
swt_modules.id,
swt_modules.name,
swt_exam_regs.name AS exam_regs
FROM swt_modules
LEFT JOIN swt_exam_regs on swt_exam_regs.id = swt_modules.exam_regulation
ORDER BY
swt_modules.name DESC,
swt_modules.id DESC
LIMIT $limit");
You need to use LEFT JOIN instead of INNER JOIN. Change your query as below. Notice that, I have removed LIMIT since you are trying to fetch all rows.
SELECT swt_modules.id, swt_modules.name, swt_exam_regs.name AS exam_regs
FROM `swt_modules`
LEFT JOIN `swt_exam_regs`
ON swt_exam_regs.id = swt_modules.exam_regulation
ORDER BY swt_modules.name DESC , swt_modules.id DESC

SQL query construction

I recently created a scoring system where the users are ordered by their points on descending basis. First I used to store ranks in a column of its own. I used to run this loop to update the rank:
$i = 1;
$numberOfRows = mysql_query('SELECT COUNT(`id`) FROM sector0_players');
$scoreboardquery = mysql_query("SELECT * FROM sector0_players ORDER BY points DESC");
while(($row = mysql_fetch_assoc($scoreboardquery)) || $i<=$numberOfRows){
$scoreid = $row['id'];
$mysql_qeury = mysql_query("UPDATE sector0_players SET scoreboard_rank = '$i' WHERE id = '$scoreid'");
$i++;
}
And it was really hard, not to mention slow to actually run this on a huge amount of users.
Instead, I tried to construct a query and ended up with this.
SET #rownum := 0;
SELECT scoreboard_rank, id, points
FROM (
SELECT #rownum := #rownum + 1 AS scoreboard_rank, id, points FROM sector0_players ORDER BY points DESC
)
as result WHERE id = '1';
But, this is just a select statement. Is there anyway I could get around it and change it so that it updates the table just as the loop does?
Please try using the following query :
set #rownum:=0;
update sector0_players set scoreboard_rank=#rownum:=#rownum+1 ORDER BY points DESC;
PHP code can be ,
mysql_query("set #rownum:=0;");
mysql_query("update sector0_players set scoreboard_rank=#rownum:=#rownum+1 ORDER BY points DESC;");
You can try using the RANK function .. I haven't actually executed the SQL, but it should work
UPDATE sector0_players
SET scoreboard_rank =
(
SELECT srank
FROM
(
SELECT id,points, RANK() OVER (ORDER BY points) AS srank
FROM sector0_players T
) D
WHERE D.id = sector0_players.id
AND D.points = sector0_players.points
)

MySQL query returns rows in mysql but empty set in PHP

The following MySQL query runs in PHP without errors, but the resultset is empty. Directly outputting the query string to a file and running the query in the MySQL client using 'source [filename]' returns several rows of results, as expected.
Is there something that would cause this query not to work with PHP? categorylinks.cl_to and smw_spec2.value_string are both varbinary(255). Show create table indicates engine=InnoDB and default charset=binary.
Things I have tried without success:
$sql = preg_replace("/[\n\t]+/", " ", $sql);
Changing '_wpg' and 'Derp' to CAST('_wpg' AS BINARY(255))
Changing '_wpg' and 'Derp' to BINARY '_wpg'
I am using the MediaWiki DatabaseMysql class to execute the query and fetch rows, but it's a very thin abstraction, and I'm certain it's not the problem (see below).
SELECT
prop.name AS prop_name, prop.count AS prop_count, prop.type AS prop_type,
val.value AS val_value, val.unit AS val_unit, val.count AS val_count
FROM
(
SELECT
s_id, name, type, COUNT(foo.name) AS count
FROM (
(
SELECT
cl.cl_to AS cat_name, s.smw_id AS s_id, s.smw_sortkey AS name, spec.value_string AS type
FROM `smw_ids` s
INNER JOIN (`categorylinks` cl, `page` p, `smw_ids` s2, `smw_atts2` a)
ON (cl.cl_from = p.page_id AND
p.page_title = s2.smw_title AND
s2.smw_id = a.s_id AND
a.p_id = s.smw_id)
LEFT JOIN `smw_spec2` spec ON s.smw_id = spec.s_id
)
UNION ALL
(
SELECT
cl.cl_to AS cat_name, s.smw_id AS s_id, s.smw_sortkey AS name, '_wpg' AS type
FROM `smw_ids` s
INNER JOIN (`categorylinks` cl, `page` p, `smw_ids` s2, `smw_rels2` a)
ON (cl.cl_from = p.page_id AND
p.page_title = s2.smw_title AND
s2.smw_id = a.s_id AND
a.p_id = s.smw_id)
)
) AS foo
WHERE foo.cat_name = 'Derp'
GROUP BY name
ORDER BY count DESC
LIMIT 10
) AS prop
INNER JOIN
(
SELECT
bar.p_id AS p_id, bar.value AS value, bar.unit AS unit, COUNT(bar.value) AS count,
IF( #prev != p_id, #rownum := 1, #rownum := #rownum+1 ) AS rank,
#prev := p_id
FROM (
(SELECT a.p_id AS p_id, a.value_xsd AS value, a.value_unit AS unit FROM `smw_atts2` a)
UNION ALL
(SELECT r.p_id AS p_id, s.smw_sortkey AS value, NULL AS unit
FROM `smw_rels2` r INNER JOIN `smw_ids` s ON r.o_id = s.smw_id)
) AS bar
GROUP BY value, unit
ORDER BY count DESC
) AS val
ON prop.s_id = val.p_id
WHERE val.rank <= 50
ORDER BY prop_count DESC, prop_name, val_count DESC, val_value
Edit: The following test script outputs nothing. query.sql contains exactly the query above, written to file immediately preceding the mysql_query() call in MediaWiki's database class.
$db = mysql_connect('localhost', 'root', '');
mysql_select_db('mediawiki', $db);
$res = mysql_query(file_get_contents("query.sql"), $db);
while ($row = mysql_fetch_assoc($res)) {
var_dump($row);
}
echo mysql_error($db);
Edit: I imported a huge database dump and afterwards, when I loaded the PHP page, there was a noticeable wait that seemed to indicate that the query was running, but still no results showed. I ended up reworking the query, and I no longer have this problem.
Try this to detect and report errors better:
$db = mysql_connect('localhost', 'root', '');
mysql_select_db('mediawiki', $db);
$res = mysql_query(file_get_contents("query.sql"), $db);
if (!$res) {
print "SQL Error ".mysql_errno().":".mysql_error().", from query: '".file_get_contents("query.sql")."'";
} else {
while ($row = mysql_fetch_assoc($res)) {
var_dump($row);
}
}
Try this after mysql_connect:
mysql_query('SET NAMES utf8;');

Echoing out a field and a value from one row while running a query that ranks all rows

I have a MySQL query called $sqlStr5 that ranks rows by a metric called totalScore2. One of the fields that $sqlStr5 returns is called username.
I would like to echo out the rank and the value of totalScore2 where username equals a variable called $u.
How can I do this?
Below is what I have so far.
Thanks in advance,
John
$result = mysql_query($sqlStr5);
$count = 1;
$arr = array();
while ($row = mysql_fetch_array($result)) {
echo '<div class="sitename1edit2a">'.$count++.'.</div>';
echo '<div class="sitename1edit2">'.number_format(($row["totalScore2"])).'</div>';
}
This should work:
$result = mysql_query($sqlStr5);
$count = 1;
while($row = mysql_fetch_array($result))
{
if($u == $row['username'])
{
echo '<div class="sitename1edit2a">'.$count.'</div>';
echo '<div class="sitename1edit2">'.number_format($row["totalScore2"]).'</div>';
}
$count++;
}
Note however that this is not the most efficient way. It should be possible to make a SQL query that returns the rank and the total score for user $u.
The following solution uses a stored procedure to work out a user's rank based on a simple ranking system which you could replace with your own more complex one.
call get_user_rank(<user_id>)
I've added another stored procedure which lists the top ten ranks and flags whether the user_id passed in is included in the top ten as I remember that being a requirement from another question of yours.
call list_top_ten_ranks(<user_id>)
Testing (call these sprocs from your php)
select count(*) from users;
count(*)
========
250000
call get_user_rank(54193);
-- 0:00:00.300: Query OK
call get_user_rank(1);
-- 0:00:00.291: Query OK
call list_top_ten_ranks(54193);
-- 0:00:00.208: Query OK
call list_top_ten_ranks(1);
-- 0:00:00.215: Query OK
PHP
$result = $conn->query(sprintf("call get_user_rank(%d)", 1));
$row = $result->fetch_assoc();
$result->close();
echo sprintf("user = %s rank = %s points = %s<br/>",
$row["user_id"],$row["rank"],$row["points"]);
$conn->close();
Hope some of this proves useful.
Script
-- TABLES
drop table if exists users;
create table users
(
user_id int unsigned not null auto_increment primary key,
points smallint unsigned not null default 0
)
engine=innodb;
-- PROCEDURES
drop procedure if exists get_user_rank;
delimiter #
create procedure get_user_rank
(
p_user_id int unsigned
)
proc_main:begin
-- replace this simple ranking method by your own
set #rank = 0;
create temporary table tmp engine=memory
select
#rank:=#rank+1 as rank,
u.user_id,
u.points
from
users u
order by
u.points desc, u.user_id;
select * from tmp where user_id = p_user_id;
drop temporary table if exists tmp;
end proc_main #
delimiter ;
drop procedure if exists list_top_ten_ranks;
delimiter #
create procedure list_top_ten_ranks
(
p_user_id int unsigned
)
proc_main:begin
-- replace this simple ranking method by your own
set #rank = 0;
set #in_top_ten = 0;
create temporary table tmp engine=memory
select
#rank:=#rank+1 as rank,
u.user_id,
u.points
from
users u
order by
u.points desc, u.user_id
limit 10;
if exists (select 1 from tmp where user_id = p_user_id) then
set #in_top_ten = 1;
end if;
select tmp.*, #in_top_ten as in_top_ten from tmp order by tmp.rank;
drop temporary table if exists tmp;
end proc_main #
delimiter ;

Categories