Building mysqli queries? - php

say if I have the query select users.user_id, users.fname, users.lname, bios.bio, groups.groupid from users LEFT JOIN bios on users.user_id = bios.userid then I want to add another table on a condition then add a where statement at the end. The problem is because when I bind the param it said 'number of variables doesn't match the number of variables in the prepare statement'. How would I solve this? Cheers. Example:
$info = "select users.user_id, users.fname, users.lname, bios.bio, groups.groupid from users LEFT JOIN bios on users.user_id = bios.userid";
$content = $members->prepare($info);
if ($_GET['where'] == 'requests') $info .= "LEFT JOIN requests on users.user_id = requests.receiver";
else if ($_GET['where'] == 'referrals') $info .= "LEFT JOIN referrals on users.user_id = referrals.receiver";
$info .= "where users.user_id = ?";
$content->bind_param('s', $_SESSION['token'][1]);
$content->execute();

You're changing the SQL string after preparing it. Don't do that. Do it like this instead:
$info = "select users.user_id, users.fname, users.lname, bios.bio, groups.groupid from users LEFT JOIN bios on users.user_id = bios.userid";
if ($_GET['where'] == 'requests') $info .= " LEFT JOIN requests on users.user_id = requests.receiver";
else if ($_GET['where'] == 'referrals') $info .= " LEFT JOIN referrals on users.user_id = requests.receiver";
$info .= " where users.user_id = ?";
$content = $members->prepare($info);
$content->bind_param('s', $_SESSION['token'][1]);
$content->execute();
Edit: Also, make sure your SQL fragments are separated with spaces where necessary; the .= operator doesn't automatically add a space for you.

Related

MYSQL alias in where clause

i have a query and i want to filter the result set using an ALIASED column in my WHERE condition, ive read that you cannnot do it but i dont have yet an alternative way to do it efficiently since im working on thousands of records.
$str = "SELECT
mainclass.id AS classid,
mainclass.code AS classcode,
Sum(CASE WHEN enroll.acctok = '1' AND enroll.assessed = '1'
THEN enroll.assessed
ELSE 0 end) AS assessedinclass,
Sum(enroll.validated = '1') AS validatedinclass,
section.name AS sectionname,
subject.code AS subcode,
subject.subdesc,
mainclass.units,
sched.name AS schedule,
mainclass.tutorial,
mainclass.dissolved,
mainclass.slots,
mainclass.ismother,
mergeclass.code AS mothercode,
mergeclass.id AS mothercodeid,
mergeclass.slots AS mothercodeslots,
mainclass.mergein,
mainclass.inst,
instructor.lname,
instructor.fname,
instructor.mname,
instructor.suffix
FROM
class AS mainclass
Left Join enrolldet ON mainclass.id = enrolldet.class
Left Join enroll ON enrolldet.enrollno = enroll.enrollno
Inner Join period ON mainclass.period = period.id
Inner Join section ON mainclass.section = section.id
Inner Join subject ON mainclass.subject = subject.id
Left Join sched ON mainclass.sched = sched.id
Left Join class AS mergeclass ON mainclass.mergein = mergeclass.id
Left Join instructor ON mainclass.inst = instructor.userid
Left Join course ON section.course = course.id
WHERE
(period.id = :period OR period.code = :period)";
if($level != ''){
$str .= " AND course.level = '".$level."'";
}
if($dept != ''){
$str .= " AND course.dept = '".$dept."'";
}
if($display != ''){
switch ($display) {
case 'open':
$str .= " AND mainclass.slots > assessedinclass";
break;
case 'dissolved':
$str .= " AND mainclass.dissolved = 1";
break;
case 'tutorial':
$str .= " AND mainclass.tutorial = 1";
break;
case 'closed':
$str .= " AND mainclass.slots <= assessedinclass";
break;
}
}
$str .= "GROUP BY
mainclass.id,
mainclass.code";
$str .= " ORDER BY subject.code, mainclass.id";
return $this->_db->select($str,array(':period' => $period));
im trying to filter it using the ASSESSEDINCLASS WHERE mainclass.slots > ASSESSEDINCLASS means the subject is OPEN
while if mainclass.slots <= ASSESSEDINCLASS it will be considered CLOSED
You can try below. Write an outer select which will have all the required columns for you to process filters.
select
classid,
classcode,
assessedinclass,
validatedinclass,
sectionname,
subcode,
subdesc,
units,
schedule,
tutorial,
dissolved,
slots,
ismother,
mothercode,
mothercodeid,
mothercodeslots,
mergein,
inst,
lname,
fname,
mname,
suffix
from
(select
mainclass.id AS classid,
mainclass.code AS classcode,
Sum(case when enroll.acctok = '1' and enroll.assessed = '1'
then enroll.assessed
else 0
end) as assessedinclass,
Sum(enroll.validated = '1') AS validatedinclass,
section.name AS sectionname,
subject.code AS subcode,
subject.subdesc,
mainclass.units,
sched.name AS schedule,
mainclass.tutorial,
mainclass.dissolved,
mainclass.slots,
mainclass.ismother,
mergeclass.code AS mothercode,
mergeclass.id AS mothercodeid,
mergeclass.slots AS mothercodeslots,
mainclass.mergein,
mainclass.inst,
instructor.lname,
instructor.fname,
instructor.mname,
instructor.suffix
from
class as mainclass
left join
enrolldet on mainclass.id = enrolldet.class
left join
enroll on enrolldet.enrollno = enroll.enrollno
inner join
period on mainclass.period = period.id
inner join
section on mainclass.section = section.id
inner join
subject on mainclass.subject = subject.id
left join
sched on mainclass.sched = sched.id
left join
class as mergeclass on mainclass.mergein = mergeclass.id
left join
instructor on mainclass.inst = instructor.userid
left join
course on section.course = course.id)
where
(period.id = :period OR period.code = :period);
Your final query would be -
select
<req_cols>
from
(select
<agg_cols>
from
table
group by
<grpCols>)
where
<filter on agg cols>
$str = "SELECT
mainclass.id AS classid,
mainclass.code AS classcode,
Sum(CASE WHEN enroll.acctok = '1' AND enroll.assessed = '1'
THEN enroll.assessed
ELSE 0 end) AS assessedinclass,
Sum(enroll.validated = '1') AS validatedinclass,
section.name AS sectionname,
subject.code AS subcode,
subject.subdesc,
mainclass.units,
sched.name AS schedule,
mainclass.tutorial,
mainclass.dissolved,
mainclass.slots,
mainclass.ismother,
mergeclass.code AS mothercode,
mergeclass.id AS mothercodeid,
mergeclass.slots AS mothercodeslots,
mainclass.mergein,
mainclass.inst,
instructor.lname,
instructor.fname,
instructor.mname,
instructor.suffix
FROM
class AS mainclass
Left Join enrolldet ON mainclass.id = enrolldet.class
Left Join enroll ON enrolldet.enrollno = enroll.enrollno
Inner Join period ON mainclass.period = period.id
Inner Join section ON mainclass.section = section.id
Inner Join subject ON mainclass.subject = subject.id
Left Join sched ON mainclass.sched = sched.id
Left Join class AS mergeclass ON mainclass.mergein = mergeclass.id
Left Join instructor ON mainclass.inst = instructor.userid
Left Join course ON section.course = course.id
WHERE
(period.id = :period OR period.code = :period)";
if($level != ''){
$str .= " AND course.level = '".$level."'";
}
if($dept != ''){
$str .= " AND course.dept = '".$dept."'";
}
if($display != ''){
switch ($display) {
case 'open':
$str .= " AND mainclass.slots > assessedinclass";
break;
case 'dissolved':
$str .= " AND mainclass.dissolved = 1";
break;
case 'tutorial':
$str .= " AND mainclass.tutorial = 1";
break;
case 'closed':
$str .= " AND mainclass.slots <= assessedinclass";
break;
}
}
$str .= "GROUP BY
mainclass.id,
mainclass.code";
$str .="HAVING <your condition>";
$str .= " ORDER BY subject.code, mainclass.id";
return $this->_db->select($str,array(':period' => $period));

PHP : Can't create automatic query

I want to build a search engine for a webpage. I use the code below. The problem is, that I have to build the queries from different strings and if the system searches for matching in strings, quote marks are needed.
$sql = "SELECT TIT,VNEV,KNEV,NEME,MEGY,LCVAR,APOLG FROM TORZS LEFT OUTER JOIN VEGZETTSEG ON TORZS.ID = VEGZETTSEG.ID LEFT OUTER JOIN SZTAPASZTALAT ON TORZS.ID = SZTAPASZTALAT.ID LEFT OUTER JOIN SZAKTANFOLYAM ON TORZS.ID = SZAKTANFOLYAM.ID LEFT OUTER JOIN INFORM ON TORZS.ID = INFORM.ID WHERE ";
for ($i = 0;$i < count($searchcategs);$i++) {
$sql = $sql . $searchcategs[$i];
$sql = $sql . " = ";
$sql = $sql . $searchvals[$i];
$sql = $sql . " ";
}
An alternative version:
$sql = "SELECT TIT,VNEV,KNEV,NEME,MEGY,LCVAR,APOLG FROM TORZS LEFT OUTER JOIN VEGZETTSEG ON TORZS.ID = VEGZETTSEG.ID LEFT OUTER JOIN SZTAPASZTALAT ON TORZS.ID = SZTAPASZTALAT.ID LEFT OUTER JOIN SZAKTANFOLYAM ON TORZS.ID = SZAKTANFOLYAM.ID LEFT OUTER JOIN INFORM ON TORZS.ID = INFORM.ID WHERE ";
for ($i = 0;$i < count($searchcategs);$i++) {
$sql = $sql . $searchcategs[$i];
$sql = $sql . " = '";
$sql = $sql . $searchvals[$i];
$sql = $sql . "' ";
}
None of them seems to work, I got
SELECT TIT,VNEV,KNEV,NEME,MEGY,LCVAR,APOLG FROM TORZS LEFT OUTER JOIN VEGZETTSEG ON TORZS.ID = VEGZETTSEG.ID LEFT OUTER JOIN SZTAPASZTALAT ON TORZS.ID = SZTAPASZTALAT.ID LEFT OUTER JOIN SZAKTANFOLYAM ON TORZS.ID = SZAKTANFOLYAM.ID LEFT OUTER JOIN INFORM ON TORZS.ID = INFORM.ID WHERE
for the query even though the searchcateg and searchval arrays are existing and not empty.

PDO Prepared Statement - Different behavior inside 2 similar methods

I would like someone to explain me why the first method works only after quoting the placeholder ':cat_id' in the WHERE clause, and requires the $this->db->query($query);, otherwise it throws fatal error:
"SQLSTATE[HY093]: Invalid parameter number: number of bound variables
does not match number of tokens in..."
while the second method doesn't need neither quoting and the $this->db->query() method?
public function getAllPosts($cat_id = null)
{
// Query build
$query = "SELECT posts.*, users.username, categories.title FROM posts "
. "INNER JOIN users "
. "ON posts.user_id = users.id "
. "INNER JOIN categories "
. "ON posts.category_id = categories.id ";
// Filter
if (!is_null($cat_id))
{
$query .= "WHERE category_id = ':cat_id' ";
// Order query
$query .= "ORDER BY create_date DESC";
$this->db->bind(':cat_id', $cat_id);
}
else
{
$query .= "ORDER BY create_date DESC";
}
$this->db->query($query);
// Run the query
// Assign Result Set
$results = $this->db->resultset();
return $results;
}
public function getCategoryPosts($cat_id)
{
$query = "SELECT posts.*, users.username, categories.title FROM posts "
. "INNER JOIN users "
. "ON posts.user_id = users.id "
. "INNER JOIN categories "
. "ON posts.category_id = categories.id "
. "WHERE posts.category_id = :cat_id "
. "ORDER BY create_date DESC";
$this->db->bind(':cat_id', $cat_id);
$results = $this->db->resultset();
return $results;
}
Update:
Here are a echo output of the query from the first method:
1. with quoted:
SELECT posts.*, users.username, categories.title FROM posts
INNER JOIN users ON posts.user_id = users.id
INNER JOIN categories ON posts.category_id = categories.id
WHERE category_id = ':cat_id' ORDER BY create_date DESC
2. unquoted:
SELECT posts.*, users.username, categories.title FROM posts
INNER JOIN users ON posts.user_id = users.id
INNER JOIN categories ON posts.category_id = categories.id
WHERE category_id = :cat_id ORDER BY create_date DESC
You are missing a trailing space on the following string
$query .= "WHERE category_id = ':cat_id'";
So you are concatenating it into:
WHERE category_id = ':cat_id'ORDER BY create_date DESC
If you remove the ', you would get:
WHERE category_id = :cat_idORDER BY create_date DESC
So PDO expects a bound value for :cat_idORDER
Also in getCategoryPosts() you create a query but never actually use it.

Mysql query is not working when I'm using concate

I don't understand why following query is not return anything. If I change the query then it's return result.
what I'm doing now (No output)
$msg = array();
$getSearch = "SELECT contact_details . * , company.company_name, users.nickname FROM contact_details LEFT JOIN users ON users.user_id = contact_details.user_id LEFT JOIN company ON company.cid = contact_details.cid WHERE";
if(!empty($ad_company)){
$getSearch .= "company.company_name LIKE '$ad_company%' ";
}
$getSearch = mysql_query($getSearch);
while($searchResult = mysql_fetch_array($getSearch)){
$msg[] = $company = $searchResult['company_name'] . "<br/>";
}
echo json_encode($msg);
Change Code(Working)
$msg = array();
$getSearch = "SELECT contact_details . * , company.company_name, users.nickname FROM contact_details LEFT JOIN users ON users.user_id = contact_details.user_id LEFT JOIN company ON company.cid = contact_details.cid WHERE company.company_name LIKE '$ad_company%'";
//$msg[] = empty($ad_company) ? "empty company" : "not empty company"; //for checking and field has value
/*if(!empty($ad_company)){
$getSearch .= "company.company_name LIKE '$ad_company%' ";
}*/
$getSearch = mysql_query($getSearch);
while($searchResult = mysql_fetch_array($getSearch)){
$msg[] = $company = $searchResult['company_name'] . "<br/>";
}
echo json_encode($msg);
Maybe becouse you don't have a space between WHERE and company?
Try this
As answer by Mitja , you have missed the space between WHERE and company
$getSearch = "SELECT contact_details . * , company.company_name, users.nickname
FROM contact_details
LEFT JOIN users ON users.user_id = contact_details.user_id
LEFT JOIN company ON company.cid = contact_details.cid ";
if(!empty($ad_company)){
$getSearch .= " WHERE company.company_name LIKE '$ad_company%' ";
}
EDITED
$getSearch = "SELECT contact_details . * , company.company_name, users.nickname
FROM contact_details
LEFT JOIN users ON users.user_id = contact_details.user_id
LEFT JOIN company ON company.cid = contact_details.cid
WHERE 1=1 ";
if(!empty($ad_company)){
$getSearch .= " AND company.company_name LIKE '$ad_company%' ";
}
I have removed the WHERE from your $getSearch query and added to the one we are appending
$getSearch = "SELECT contact_details . * , company.company_name, users.nickname FROM contact_details LEFT JOIN users ON users.user_id = contact_details.user_id LEFT JOIN company ON company.cid = contact_details.cid";
if(!empty($ad_company)){
$getSearch .= " WHERE company.company_name LIKE '$ad_company%' ";
}
in future if you face problems like these always try to print only sql query before querying it with db.. this way you will get to see as if your query is correct or not

MySQL left join not working with AS keyword

I like to use self explaining names for associative selects, and sometimes it's even mandatory to avoid duplicates, so I use the AS keyword alot. But it's giving me some trouble with left joins.
This works:
$sql = "SELECT *,
projects.id as projects_id
FROM projects";
$sql .= " LEFT JOIN".
" (SELECT
projectfiles.id as projectfiles_id,
projectfiles.fileID as projectfiles_fileID,
projectfiles.projectID as projectfiles_projectID
FROM projectfiles
) AS projectfiles".
" ON projects.id = projectfiles_projectID";
However now I end up with useless data from projects, because it also picks up the fields userID and name, which I don't need. It's also picking up the id twice.
So I tried changing it to;
$sql = "SELECT
projects.id as projects_id
FROM projects";
With the ON line becoming
" ON projects_id = projectfiles_projectID";
But that gave the error Unknown column projects_id
So I tried
" ON projects.projects_id = projectfiles_projectID";
But still the same error
I then started experimenting, and tried (as a test)
$sql = "SELECT id,name,userID FROM projects";
$sql .= " LEFT JOIN".
" (SELECT
projectfiles.id as projectfiles_id,
projectfiles.fileID as projectfiles_fileID,
projectfiles.projectID as projectfiles_projectID
FROM projectfiles
) AS projectfiles".
" ON projects.id = projectfiles_projectID";
And to my surprise, the LEFT JOIN didn't seem to pick up anything at all.
Code:
$sql = "SELECT id,name,userID FROM projects";
$sql .= " LEFT JOIN".
" (SELECT
projectfiles.id as projectfiles_id,
projectfiles.fileID as projectfiles_fileID,
projectfiles.projectID as projectfiles_projectID
FROM projectfiles
) AS projectfiles".
" ON projects.id = projectfiles_projectID";
$res = mysql_query($sql);
if(!$res) die(mysql_error());
if(mysql_num_rows($res) > 0)
{
$rownum = 0;
while($row = mysql_fetch_assoc($res))
{
print_r($row);
echo "<br/><br/>";
$rownum++;
}
}
Output:
Which is weird because there is only one row in projects but 3 in projectfiles with that projectID... what am I doing wrong?
To select only from the projectfiles table:
$sql = "SELECT projectfiles.*,
projects.id as projects_id
FROM projects";
// rest of the code is the same
Update
$sql = "SELECT projectfiles.* FROM projects";
// rest of the code is the same
Use short form of the query:
$sql = "SELECT projects.id,projects.name,projects.userID FROM projects LEFT JOIN
projectfiles ON projects.id = projectfiles.projectID";
SELECT p.*, pf.id, pf.fileId
FROM projects p LEFT JOIN projectfiles pf
on p.id = pf.projectID
You can use "as" to do as you will then. No need for a subselect.
$sql = "SELECT p.id,p.name,p.userID FROM projects p";
$sql .= " LEFT JOIN".
" projectfiles pf ".
" ON p.id = p.projectID";
$sql = "SELECT prj.id as prjId,
prj.name as prjName,
prj.userID as prjUid,
pf.id as pfId,
pf.fileID as pfFileId,
pf.projectID as pfProjecId
FROM projects as prj
LEFT JOIN projectfiles AS pf
ON prj.id = pf.projectID";

Categories