MySQL GROUP BY is not working in PDO prepared statement [duplicate] - php

This question already has answers here:
Why does this PDO statement silently fail?
(2 answers)
Closed 1 year ago.
I have two statements: one is written with mysql_query, another with PDO:
mysql_query:
$sql = $mysql_query("SELECT `user_report`.* FROM `user_report` LEFT JOIN `user` ON
`user_report`.`user_id` = `user`.`user_id` WHERE `user`.`userBlocked` = 0 GROUP BY
`user_id` ORDER BY `reports` DESC, `user_report`.`timestamp` ASC");
PDO prepared:
$sql = $pdo->prepare("SELECT `user_report`.* FROM `user_report` LEFT JOIN `user` ON
`user_report`.`user_id` = `user`.`user_id` WHERE `user`.`userBlocked` = 0 GROUP BY
`user_id` ORDER BY `reports` DESC, `user_report`.`timestamp` ASC");
$sql->execute();
PDO doesn't work with GROUP BY user_id.
Reason I need it is if two results come with the same user_id I want to show it as one.
How is it possible that PDO doesn't allow GROUP BY function ... in MySQL statement is there any substitute to that?
Thank you.

Try this
$sql = $pdo->prepare("SELECT user_report.* FROM `user_report` LEFT JOIN `user` ON
user_report.user_id = user.user_id WHERE user.userBlocked = 0 GROUP BY
user.user_id DESC, user_report.timestamp ASC");
$sql->execute();
changes i did `` removing on selecting tables and
GROUP BY is pointing to which can be (user.user_id or user_report.user_id) you need to confirm?
AND ORDER BY (reports) is pointing to ? so i removed ?
You try the above sql, and provide your output if there is any error.

Related

Query works in phpmyadmin but same query won't return in PHP script

This is NOT a duplicate. None of the already existing threads have the same problem as me.
I have a database that stores athlete performances. It contains sessions, each session has sets, each set has "tables" (such as 4x100m, 12x50m and so on), and each table has times. I also have a table for athletes. Each athlete has an ID, each time links with the athlete through the AthleteID. Every session, set, timetable and time also have each unique IDs, used to link them with each other.
I want to make it so that when passing a session ID, it will return all the athletes that have at least 1 time in that session. I made a page that gets requests and the session ID is passed as GET search data (will make it POST later on). The request system works fine, but the problem is in the query. To do it I used inner joins to connect each table. This is my query (it is not the fastest method, but that's for another thread):
$q = "SET #evID = " . $method['sessID'] . ";";
$q .= "SELECT `athletes`.* FROM `events`
INNER JOIN `sets` ON `sets`.`EventID` = `events`.`EventID`
INNER JOIN `timetables` ON `timetables`.`SetID` = `sets`.`SetID`
INNER JOIN `times` ON `times`.`TableID` = `timetables`.`TableID`
INNER JOIN `athletes` ON `athletes`.`ID` = `times`.`AthleteID`
WHERE `events`.`EventID` = #evID
AND `times`.`TimeID` IN(
SELECT MIN(`TimeID`)
FROM `times`
WHERE `TableID` IN(
SELECT `TableID`
FROM `timetables`
WHERE `SetID` IN(
SELECT `SetID`
FROM `sets`
WHERE `EventID` = #evID
)
)
GROUP BY `AthleteID`
)";
Every single time I ran that in phpmyadmin it returned all the athletes, and the data was correct. However, when I run it in my script, the query value is false (such as if there is an error). I tried debugging like this:
$r = $db -> query($q);
var_dump($q);
var_dump($r);
var_dump($db->error);
The query is returned just fine (only difference is lack of newline characters), and when I copy what's returned in phpmyadmin the data is just the same. The rest however:
bool(false)
string(228) "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT `athletes`.* FROM `events` INNER JOIN `sets` ON `sets`.`EventID` = `...' at line 1"
Other users with the same problem have not really gone that far to find out if they're wrong, but I have. This post is not a duplicate, and I didn't find any solutions online. Could this be a problem with the amount of queries in a single string? (There is one for setting #evID and one for the actual selection). Please explain the solution and methods kindly as I'm only 13 and still learning...
As #NigelRen has suggested, please use parameterized prepared statement.
Assuming that
$sessionid is storing the value for EventID, and assuming that this variable is of integer type; and
$conn is the connection
Then for Mysqli, you can use:
//$q = "SET #evID = " . $method['sessID'] . ";";
$sql = "SELECT `athletes`.* FROM `events`
INNER JOIN `sets` ON `sets`.`EventID` = `events`.`EventID`
INNER JOIN `timetables` ON `timetables`.`SetID` = `sets`.`SetID`
INNER JOIN `times` ON `times`.`TableID` = `timetables`.`TableID`
INNER JOIN `athletes` ON `athletes`.`ID` = `times`.`AthleteID`
WHERE `events`.`EventID` = ?
AND `times`.`TimeID` IN(
SELECT MIN(`TimeID`)
FROM `times`
WHERE `TableID` IN(
SELECT `TableID`
FROM `timetables`
WHERE `SetID` IN(
SELECT `SetID`
FROM `sets`
WHERE `EventID` = ?
)
)
GROUP BY `AthleteID`
)";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ii", $sessionid, $sessionid);
$stmt->execute();
$result = $stmt->get_result(); // get the mysqli result
$row = $result->fetch_assoc(); // fetch data
// do other things you want , such as echo $row['fieldname1'];

Using A PDO Prepared Statement On A Search Form Query - PHP [duplicate]

This question already has answers here:
How do I create a PDO parameterized query with a LIKE statement?
(9 answers)
Closed 10 months ago.
I have some images that are outputted onto a page with PHP from a MySQL database. The while loop that outputs them includes a join because it gets data from two database tables (an imageposts table and a users table).
With the current output a query is run, but because there is no user input it uses the following code:
<?php
// IMAGE GRID JOIN
$stmt = $connection->query("SELECT imgp.*, u.id, u.firstname, u.lastname
FROM imageposts AS imgp
INNER JOIN users AS u ON imgp.user_id = u.id");
while ($row = $stmt->fetch()) {
// from imageposts table
$db_image_id = htmlspecialchars($row['image_id']);
$db_image_title = htmlspecialchars($row['image_title']);
$db_image_filename = htmlspecialchars($row['filename']);
$db_ext = htmlspecialchars($row['file_extension']);
$db_username = htmlspecialchars($row['username']);
// from users table
$db_firstname = htmlspecialchars($row['firstname']);
$db_lastname = htmlspecialchars($row['lastname']);
?>
-- HTML OUTPUT
<?php } ?>
The Issue
I'm also setting up my first search form for the site, and when the images are outputted I want them to pull in the same information as above (in addition to the search query), but because it's a search form and has user input, I'm going to need to use a prepared statement, and I cannot get my head around how to approach this?
The search will take place on the image_title column of the imageposts table, so in terms of sudo code it would be:
$searchSQL = "SELECT * FROM `imageposts` WHERE `image_title` LIKE %$searchQuery% ";
where the $searchQuery is the value of a search input field.
But how do I integrate that with the query in the first section of this question, and also use a prepared statement for security?
Would the MySQL be this?:
"SELECT imgp.*, u.id, u.firstname, u.lastname
FROM imageposts AS imgp
INNER JOIN users AS u ON imgp.user_id = u.id WHERE image_title LIKE %$searchQuery%"
And if so, how do I make it secure in terms of the prepared statement on the $searchQuery?
Alternative 1:
$sql = "SELECT imgp.*, u.id, u.firstname, u.lastname
FROM imageposts AS imgp
INNER JOIN users AS u ON imgp.user_id = u.id
WHERE image_title LIKE CONCAT('%', ?, '%')";
$stmt = $connection->prepare($sql);
$stmt->execute([$searchQuery]);
Alternative 2:
$sql = "SELECT imgp.*, u.id, u.firstname, u.lastname
FROM imageposts AS imgp
INNER JOIN users AS u ON imgp.user_id = u.id
WHERE image_title LIKE ?";
$stmt = $connection->prepare($sql);
$stmt->execute(["%{$searchQuery}%"]);

PHP Prepared Statement variable binding error with subquery

I have a query with a few subqueries like so
SELECT ...
FROM (SELECT ...
FROM ...
GROUP BY ...) as speedLimitCalc INNER JOIN
(SELECT ...
FROM date a INNER JOIN HOURLY_TEST b ON a.[FULL_DAY_DT] = b.DATE
WHERE (b.DATE BETWEEN '".$date_s."' AND '".$date_e."')
AND HOUR BETWEEN ".$time_s." AND ".$time_e."
AND(LKNO BETWEEN '".$lkno_s."' and '".$lkno_e."')
AND RDNO= '".$rdno."'
AND pub_hol IN (".$pubholquery.")
AND school_hol IN (".$schholquery.")
AND day_no IN (".$dayquery.")
GROUP BY RDNO, LKNO, PRESCRIBED_DIRECTION, CWAY_CODE) as origtable ON ...
,(SELECT ...
FROM [Dim_date]
WHERE (FULL_DAY_DT BETWEEN '".$date_s."' AND '".$date_e."')
AND pub_hol IN (".$pubholquery.")
AND school_hol IN (".$schholquery.")
AND day_no IN (".$dayquery.") ) as c
ORDER BY ...
where I am inserting variables in the inner query where clause.
I am trying to parametrize this query using odbc_prepare and odbc_execute, however I am running into issues of binding the variables. At present, when I use the following
$result = odbc_prepare($connection, $query);
odbc_execute($result)or die(odbc_error($connection));
to run this query, everything works fine. However, when I try to bind a variable, such as
AND RDNO= ?
...
odbc_execute($result, array($rdno))or die(odbc_error($connection));
I get the following error message.
PHP Warning: odbc_execute() [/phpmanual/function.odbc-execute.html]: SQL error: [Microsoft][ODBC SQL Server Driver]Invalid parameter number, SQL state S1093 in SQLDescribeParameter
My guess is that it's because I'm binding a variable in a subquery, since this procedure works when the Where clause is in the top Select query.
I was wondering whether anyone else has encountered this issue before, and how they solved it? Thanks
Fixed the issue by removing the need for parameters in the subquery by separating the query into multiple queries using temporary tables.
$query = "SELECT ...
INTO ##avgspeedperlink
FROM Date a INNER JOIN HOURLY_TEST ON a.[FULL_DAY_DT] = b.DATE
WHERE (b.DATE BETWEEN ? AND ?)
AND HOUR BETWEEN ? AND ?
AND(LKNO BETWEEN ? and ?)
AND RDNO= ?
AND pub_hol IN (".$pubholquery.")
AND school_hol IN (".$schholquery.")
AND day_no IN (?,?,?,?,?,?,?)
GROUP BY RDNO, LKNO, PRESCRIBED_DIRECTION, CWAY_CODE";
$result = odbc_prepare($connection, $query);
odbc_execute($result, array($date_s,$date_e,$time_s,$time_e,$lkno_s,$lkno_e,$rdno,$daysanitised[0],$daysanitised[1],$daysanitised[2],$daysanitised[3],$daysanitised[4],$daysanitised[5],$daysanitised[6]))or die(odbc_error($connection));
$query = "SELECT ...
INTO ##daysinperiod
FROM [RISSxplr].[dbo].[Dim_date]
WHERE (FULL_DAY_DT BETWEEN ? AND ?)
AND pub_hol IN (".$pubholquery.")
AND school_hol IN (".$schholquery.")
AND day_no IN (?,?,?,?,?,?,?)";
$result = odbc_prepare($connection, $query);
odbc_execute($result, array($date_s,$date_e,$daysanitised[0],$daysanitised[1],$daysanitised[2],$daysanitised[3],$daysanitised[4],$daysanitised[5],$daysanitised[6]))or die(odbc_error($connection));
$query = "SELECT ...
FROM ##avgspeedperlink, ##daysinperiod
ORDER BY LKNO, OUTBOUND
drop table ##avgspeedperlink
drop table ##daysinperiod";
Note that I had to use double ## for making the temporary tables (single # means that table is local to the query, ## means that the temporary table becomes global for multiple queries).

PDO MYSQL nested COUNT breaks my query

I have query like this:
$query = $con->prepare("SELECT `Id`,
(SELECT count(`Id`)
FROM `images`
WHERE `parentId` = :recId) as `numImgs`
FROM `records`
WHERE `id`= :recId LIMIT 1");
$query->execute(array('recId' => $recId));
$rec = $query->fetch(PDO::FETCH_ASSOC);
When I do this without the nested (SELECT Count(Id)) the query works.
If I take out the SELECT(COUNT(Id)) and do it on it's own, it also works.
For some reason the above query doesn't work. I don't get any errors, just no results. However if I run the query inside phpMyAdmin, it works without any problem and returns two columns, Id and numImgs, eg:
----------------
| id | numImgs |
----------------
| 50 | 10 |
----------------
I've tested the value I'm passing, it is being correctly populated from $recId so there's no issue there. Can anyone point me in the right direction as to what's going wrong with this?
Thanks!
NOTE: this works perfectly, but I don't understand why I can't do it with one query:
try{
$query = $con->prepare("SELECT `Id`
FROM `records`
WHERE `id`= :recId
AND `ownerId` = :userId
LIMIT 1");
$query->execute(array('recId' => $recId, 'userId' => $userId));
$rec = $query->fetch(PDO::FETCH_ASSOC);
}catch(PDOException $e) {
dump_exception('Exception selecting record.', $e);
}
if($rec){
try{
$picQuery = $con->prepare("SELECT COUNT(`Id`)
FROM `images`
WHERE `parentId`= :recId");
$picQuery->execute(array('recId' => $recId));
$numPics = $picQuery->fetchColumn();
}catch(PDOException $e) {
dump_exception('Exception counting pictures.', $e);
}
Can't you use JOINs and GROUP BY? It would look like this if I got your question right.
SELECT `id`, COUNT(*) AS `numImgs`
FROM `records` r
INNER JOIN `images` i ON i.parentId = r.id
WHERE r.id = :recId
AND r.ownerId = :userId
GROUP BY r.id
LIMIT 1
Looks like I've found the problem thanks to #RyanVincent's comment below. Whilst I have other working queries which use the same parameter more than once without it having to be passed into the "execute" array more than once, in this case, it seems that only listing the parameter once is causing the issue. I suspect that because it's a nested query, it treats it as two independent queries and as such, one has no access to the parameters of another. That's just a guess, I may be wrong, but it seems to make sense based on my results. Not only does the parameter have to be listed twice, but it must also be uniquely named otherwise you get exactly the same problem. So this code fixed the problem:
$query = $con->prepare("SELECT `Id`,
(SELECT count(`Id`)
FROM `images`
WHERE `parentId` = :recIdOne) as `numImgs`
FROM `records`
WHERE `id`= :recIdTwo LIMIT 1");
$query->execute(array('recIdOne' => $recId, 'recIdTwo' => $recId));
$rec = $query->fetch(PDO::FETCH_ASSOC);

PDO fetch returns nothing [duplicate]

This question already has answers here:
PHP PDOException: "SQLSTATE[HY093]: Invalid parameter number"
(4 answers)
Closed 8 years ago.
I've encountered a little problem.
I have the following code:
$query = $db->prepare('(SELECT last_visit, last_ip FROM user_log WHERE user_id = :id)
UNION
(SELECT time AS last_visit, packet_hex AS last_ip FROM crack_log WHERE target_id = :id)
ORDER BY last_visit DESC LIMIT 0,10;');
$query->execute(array(':id'=> $_SESSION['id']));
$log = $query->fetchAll(PDO::FETCH_ASSOC); //Last visit/IP
var_dump($log);
Which returns:
array(0) { }
I've tried the query in phpmyadmin and it worked fine. Can you please help me find the error?
Accorrding to the documentation
You cannot use a named parameter marker of the same name twice in a
prepared statement.
You cannot bind multiple values to a single named parameter in, for
example, the IN() clause of an SQL statement.
In you case, you should use something like
$query = $db->prepare('(SELECT last_visit,
last_ip
FROM user_log
WHERE user_id = :id_1
)
UNION
(SELECT time AS last_visit,
packet_hex AS last_ip
FROM crack_log
WHERE target_id = :id_2
)
ORDER BY last_visit DESC LIMIT 0,10;'
);
$query->execute(array(':id_1'=> $_SESSION['id'],
':id_2'=> $_SESSION['id']
)
);

Categories