I found myself in a really weird situation in PDO. A query doesn't want to execute when called from PhP but it does when called from HeidiSQL.
The error is in title.
SQL query from statement debugDumpParams :
SELECT s_id AS id,
s_title AS title,
genre.g_name AS genreName,
accounts.ac_public_name AS producerName,
s_price AS price,
DATE_FORMAT(s_last_modified_date, '%d/%m/%Y %H:%i:%s') AS lastModifiedDate,
DATE_FORMAT(s_added_date, '%d/%m/%Y %H:%i:%s') AS addedDate,
s_downloads AS downloads,
s_sales AS sales,
s_rating AS rating,
s_status AS STATUS
FROM song
JOIN accounts ON accounts.ac_id = song.s_producer
JOIN genre ON genre.g_id = song.s_genre
WHERE 1=1 AND genre.g_id = '1'
ORDER BY s_status ASC, s_added_date DESC
LIMIT 0, 5;
Next is the part where I add genre.g_id = :id in the query string
if(isset($filterData["genreId"]) && $filterData["genreId"] !== ""){
$queryString .= " AND genre.g_id = :genreId";
}
And where I bind it
if(isset($filterData["genreId"]) && $filterData["genreId"] !== ""){
$genreParam = $filterData["genreId"];
$stmt->bindParam('genreId', $genreParam);
}
In both cases $filterData["genreId"] is set and it have a value, so no problems with the if. And if $filterData["genreId"] would be empy or not set there would be no problem with the query.
And the error : SQLSTATE[42S22]: Column not found: 1054 Unknown column \'genre.g_id\' in \'where clause\'
But wait, there is more.
If I put genre.g_id2 instead of genre.g_id it will look like this:
if(isset($filterData["genreId"]) && $filterData["genreId"] !== ""){
$queryString .= " AND genre.g_id2 = :genreId";
}
Now it won't even reach $stmt->debugDumpParams();
And all it gives out it's this error: SQLSTATE[42S22]: Column not found: 1054 Unknown column \'genre.g_id2\' in \'where clause\ , no query like before.
The column 100% exists in the table. Similar problem whith this query:
SELECT s_id AS id,
s_title AS title,
genre.g_name AS genreName,
accounts.ac_public_name AS producerName,
s_price AS price,
DATE_FORMAT(s_last_modified_date, '%d/%m/%Y %H:%i:%s') AS lastModifiedDate,
DATE_FORMAT(s_added_date, '%d/%m/%Y %H:%i:%s') AS addedDate,
s_downloads AS downloads,
s_sales AS sales,
s_rating AS rating,
s_status AS STATUS
FROM song
JOIN accounts ON accounts.ac_id = song.s_producer
JOIN genre ON genre.g_id = song.s_genre
WHERE 1=1 AND accounts.ac_id = '999999'
ORDER BY s_status ASC, s_added_date DESC
LIMIT 0, 5;
It seems the problem is only with columns that are from the tables that table song JOIN with.
Next query works perfectly.
SELECT s_id AS id,
s_title AS title,
genre.g_name AS genreName,
accounts.ac_public_name AS producerName,
s_price AS price,
DATE_FORMAT(s_last_modified_date, '%d/%m/%Y %H:%i:%s') AS lastModifiedDate,
DATE_FORMAT(s_added_date, '%d/%m/%Y %H:%i:%s') AS addedDate,
s_downloads AS downloads,
s_sales AS sales,
s_rating AS rating,
s_status AS STATUS
FROM song
JOIN accounts ON accounts.ac_id = song.s_producer
JOIN genre ON genre.g_id = song.s_genre
WHERE 1=1 AND s_status = '0'
ORDER BY s_status ASC, s_added_date DESC
LIMIT 0, 5;
2 days on this and no solutons. Most solutions I find are to check again if the column really exists :|
Does any one have a better solution for this specific problem ?
The goal is to select the data where the g_id is equal with the value I pass to it.
How I create the query string:
$queryString = "SELECT s_id as id,
s_title as title,
genre.g_name as genreName,
accounts.ac_public_name as producerName,
s_price as price,
DATE_FORMAT(s_last_modified_date, '%d/%m/%Y %H:%i:%s') as lastModifiedDate,
DATE_FORMAT(s_added_date, '%d/%m/%Y %H:%i:%s') as addedDate,
s_downloads as downloads,
s_sales as sales,
s_rating as rating,
s_status as status
FROM song
JOIN accounts on accounts.ac_id = song.s_producer
JOIN genre on genre.g_id = song.s_genre
WHERE 1=1 ";
then in a function I add this
if(isset($filterData["genreId"]) && $filterData["genreId"] !== ""){
$queryString .= " AND genre.g_id = :genreId";
}
then I do this
$queryString .= " ORDER BY s_status asc, s_added_date desc";
$queryString .= " LIMIT :offset, :limit;";
and finally
$stmt = $dbConnector->getConnection()->prepare($queryString);
This is the part that is related to the problem. I can't post the entire function, it's really long.
This is used to search data based on some inputs or combinations of inputs. The entire DAO class is really big :)
OS: Windows 10,
PhP version: 7.2.19,
Apache version: 2.4.35,
MariaDB version: 10.4
Heidi SQL: 10.2.0.5599
One more edit:
If I add the columun in the queryString when I first declare it:
$queryString = "SELECT s_id as id,
s_title as title,
genre.g_name as genreName,
accounts.ac_public_name as producerName,
s_price as price,
DATE_FORMAT(s_last_modified_date, '%d/%m/%Y %H:%i:%s') as lastModifiedDate,
DATE_FORMAT(s_added_date, '%d/%m/%Y %H:%i:%s') as addedDate,
s_downloads as downloads,
s_sales as sales,
s_rating as rating,
s_status as status
FROM song
JOIN accounts on accounts.ac_id = song.s_producer
JOIN genre on genre.g_id = song.s_genre
WHERE 1=1 AND genre.g_id = :genreId";
$queryString = $this->filterDataQuery($queryString, $filterData, "songs");
$queryString .= " ORDER BY s_status asc, s_added_date desc";
$queryString .= " LIMIT :offset, :limit;";
$stmt = $dbConnector->getConnection()->prepare($queryString);
$genreParam = $filterData["genreId"];
$stmt->bindParam(':genreId', $genreParam);
and not inside $this->filterDataQuery($queryString, $filterData, "songs"); when I build the queryString based on selected filters it works perfectly.
This is the select from the browser console now:
SELECT s_id AS id,
s_title AS title,
genre.g_name AS genreName,
accounts.ac_public_name AS producerName,
s_price AS price, DATE_FORMAT(s_last_modified_date, '%d/%m/%Y %H:%i:%s') AS lastModifiedDate, DATE_FORMAT(s_added_date, '%d/%m/%Y %H:%i:%s') AS addedDate,
s_downloads AS downloads,
s_sales AS sales,
s_rating AS rating,
s_status AS STATUS
FROM song
JOIN accounts ON accounts.ac_id = song.s_producer
JOIN genre ON genre.g_id = song.s_genre
WHERE 1=1 AND genre.g_id = '1'
ORDER BY s_status ASC, s_added_date DESC
LIMIT 0, 5;
Isn't this one the same with the first? For it is. I am blind ?
After rereading your first post dozens of times and testing locally all sorts of normal things without getting the same error, I think the $stmt variable inside filterDataQuery() holds a total different query than posted here. And it just doesn't include the table genre as shown in the error message.
If you're not using that function, seeing your second last code block, all works well (if I understand you correctly).
Also according to the code shown, I don't understand how you would call filterDataQuery() to add criteria to the querystring, and directly binding the params to the statement object that's prepared later on and thus is not available there (or not the one you would expect).
To prove my theory my complete test code, still using this db-fiddle:
ini_set('display_errors', 1);
error_reporting(E_ALL);
$DB_USER = '*****';
$DB_PASS = '*****';
$db = new PDO('mysql:host=localhost;dbname=testing.project', $DB_USER, $DB_PASS);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$select = 'SELECT s_id AS id,
s_title AS title,
genre.g_name AS genreName,
accounts.ac_public_name AS producerName,
s_price AS price,
DATE_FORMAT(s_last_modified_date, "%d/%m/%Y %H:%i:%s") AS lastModifiedDate,
DATE_FORMAT(s_added_date, "%d/%m/%Y %H:%i:%s") AS addedDate,
s_downloads AS downloads,
s_sales AS sales,
s_rating AS rating,
s_status AS STATUS
FROM song
JOIN accounts ON accounts.ac_id = song.s_producer
JOIN genre ON genre.g_id = song.s_genre';
$where = ' WHERE genre.g_id = :genreId';
$order = ' ORDER BY s_status ASC, s_added_date DESC';
$limit = ' LIMIT 0, 5';
// No problemo:
$sql = $select . $where . $order . $limit;
$stmt = $db->prepare($sql);
$genreId = 1;
$stmt->bindParam(':genreId', $genreId);
$stmt->execute();
// Trigger error column not found, $stmt containing an unexpected query:
$select = 'SELECT * FROM `song`';
$sql = $select . $where . $order . $limit;
$stmt = $db->prepare($sql);
$genreId = 1;
$stmt->bindParam(':genreId', $genreId);
$stmt->execute();
First, I don't pass the $stmt variable to filterDataQuery. I pass it to bindParams. bindParams function is called aftert filterDataQuery is done and after adding the strings for order by and limit.
I really have to thank you,Piemol , for trying to help me.
I checked Maria DB logs after a professor from my college adviced me to do so, and I found the problem there
In the same controller I was calling two DAO methods, one after another, one to bring the data, and the sencond to do a count.
$responseMessage = json_encode(AdminDAO::getInstance()->getFilteredSongsList($message));
$count = AdminDAO::getInstance()->getFilteredSongsListItemsCount($message); // this one was the problem
The problem was not in the one that was getting the data, the one I posted about. The problem was with the one doing the count. I did not added the joins there :| .
Alose there where no indication from what method the error was comming so I focused on the wrong one(the one that was displayed in log). Something like this would have never happened if I would have used a logger like I do in Java.
Here are the queries from MariaDB log file: https://www.heypasteit.com/clip/0IUPWG
First one is the one that fails and the 2nd one is the one that works.
I miss log4j from Java so much.
Thanks to everybody who tried to help me.
For those who have this kind of weird problems, check logs, put echos, don't focus on the first thing you see in a AJAX response log.
How to not exist on another table on this two table?
Users table
User_relationships table
and this is my current query
"SELECT * FROM `users`
WHERE CONCAT(first_name, " ", last_name) LIKE '%' . $name . '%'
AND (`role_id` = 6 OR `role_id` = 4)
ORDER BY `first_name` asc limit 15"
and I want to add on query where guardian_id(user_id) not exist on the user_relationships table
UPDATE 1
select * from `users`
where not exists
(select 1 from `user_relationships`
inner join `users` on `user_relationships`.`guardian_id` = `users`.`id`
where `user_relationships`.`student_id` = 422)
I tried this and still returns me zero result.
I only have var name = ? and student_id = ?
try to use "NOT IN" query function with 'DISTINCT'.
following may help you.
select * from users where CONCAT(first_name, " ", last_name) LIKE '%' . $name . '%' and (role_id= 6 or role_id= 4) and (id NOT IN (select DISTINCT guardian_id from User_relationships where student_id = $student_id)) order by first_name ASC limit 15
Let me know if you still need some changes.
I have four tables:
tournaments (id, name, slots, price, gameId, platformId)
games (id, name)
platforms (id, name)
participations (id, tournamentId, playerId)
I want to get tournament's game name, platform name, slots, price, reservedSlots (participations count), information whether some player (his id is provided by php) participate in this tournament (bool/true) and conditions are:
- gameId must be in specified array provided by php
- platformId must be in specified array provided by php
I have created something like this but it doesn't work correctly:
php:
$platformsList = "'". implode("', '", $platforms) ."'"; //
$gamesList = "'". implode("', '", $games). "'";
mysql:
SELECT
t. NAME AS tournamentName,
t.id,
t.slots,
p. NAME,
g. NAME AS gameName,
t.price
FROM
tournaments AS t,
platforms AS p,
games AS g,
participations AS part
WHERE
t.PlatformId = p.Id
AND t.GameId = g.Id
AND t.Slots - (
SELECT
count(*)
FROM
participations
WHERE
TournamentId = t.id
) > 0
AND part.TournamentId = t.Id
AND t.PlatformId IN ($platformsList)
AND t.GameId IN ($gamesList)
I will not dwelve into handling your post and get values, I will assume that everything is all right:
$possibleGameIDs = getPossibleGameIDs(); //function will return the array you need for possible game id values. Inside your function make sure that the id values are really numeric
$possiblePlatformIDs = getPossiblePlatformIDs(); //function will return the array you need for possible platform id values. Inside your function make sure that the id values are really numeric
$playerId = getPlayerId(); //function returns the player id and makes sure that it is really a number
$sql = "select games.name, platforms.name, tournaments.slots, tournaments.price, ".
"(select count(*) from participations where participations.tournamentId = tournaments.tournamentId) as reservedSlots, ".
"(select count(*) > 0 from participations where participations.tournamentId = tournaments.tournamentId and playerId = ".$playerId.") as isParticipating ".
"from tournamens ".
"join games ".
"on tournaments.gameId = games.id ".
"join platforms ".
"on tournaments.platformId = platforms.id ".
"where games.id in (".implode(",", $possibleGameIDs).") and ".
" platforms.id in (".implode(",", $possiblePlatformIDs).") and ".
" tournaments.slots > 0"
Code was not tested, so please, let me know if you experience any problems using it. Naturally you need to run it, but as you did not specify what do you use to run the query, I did not allocate time to deal with technical details of running it. Beware SQL injections though.
I would like to display the data that belongs to any of my users when they login to the site, as well as the name of each table (they completed offers on them).
This is the code I used, but when I add it it's not working.
$result = mysql_query('SELECT *,\'tbl1\' AS tablename FROM (SELECT * FROM table1 WHERE user_id='$user_id') as tbl1 UNION SELECT *,\'tbl2\' AS tablename FROM (SELECT * FROM table1 WHERE user_id='$user_id') as tbl2'. ' ORDER BY `date` DESC');
while($sdata = mysql_fetch_array($result)){
echo $sdata['date'];
echo $sdata['tablename'];
echo $sdata['user_reward'];
}
Where did I make a mistake?
You are missing the concatenation operators here, around $user_id:
$result = mysql_query(
'SELECT *,\'tbl1\' AS tablename FROM (
SELECT * FROM table1 WHERE user_id=' . $user_id . '
) as tbl1
UNION
SELECT *,\'tbl2\' AS tablename FROM (
SELECT * FROM table1 WHERE user_id=' . $user_id . '
) as tbl2' . ' ORDER BY `date` DESC'
);
I've wrapped the call for more clarity - I suggest you do the same in your own code. I'd be inclined to use " marks here instead, so you don't need to escape apostrophes.
The ORDER BY clause seems to be redundantly concatenated as well - remove the dot and add this part of the query to the as tbl2 part.
Here's how I would do it:
$sql = "
SELECT *, 'tbl1' AS tablename FROM (
SELECT * FROM table1 WHERE user_id={$user_id}
) as tbl1
UNION
SELECT *, 'tbl2' AS tablename FROM (
SELECT * FROM table1 WHERE user_id={$user_id}
) as tbl2
ORDER BY `date` DESC
";
$result = mysql_query($sql);
Make sure that $user_id is properly escaped or cast, to avoid security problems. Also, this database library is no longer recommended, and will be removed in a future version of PHP. It would be better to move to PDO or mysqli, and use parameterisation.
Finally, it does rather look like the query itself is rather cumbersome - it looks like it could be simplified. Perhaps ask a separate question on that?
I have 2 tables; members and teams
members table
memberID, firstName, lastName
(firstName and lastName are fulltext indexes)
teams table
team_id, member1ID, member2ID
Here's my query
$sql = "SELECT a.* ";
$sql .= "FROM teams a WHERE ";
$sql .= "a.member1ID IN (SELECT b.memberID FROM members b ";
$sql .= "WHERE MATCH(b.firstName, b.lastName) AGAINST('$q' IN BOOLEAN MODE)) ";
$sql .= "OR a.member2ID IN (SELECT b.memberID FROM members b ";
$sql .= "WHERE MATCH(b.firstName, b.lastName) AGAINST('$q' IN BOOLEAN MODE)) ";
if($year)
$sql .= "AND a.team_y = $year ";
$sql .= "ORDER BY a.team_num ASC ";
if($limit)
$sql .= "$limit";
This query has to be close, but its not working yet.
Im trying to build a query that will let me show me all of the teams "$q" is on.
Ex. $q=doe , Show me all teams that doe is on.
This query has to output the teams.
One possible reason your query doesn't work is there is a minimum length on full-text searching, which defaults to 4 characters. "doe" would fail this match. You can increase this via variable "ft_min_word_len"
http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_ft_min_word_len
By the way, if you want to avoid Normalizing (which isn't always the "best" way to go), you could at least use JOIN's instead of sub-selects.. e.g. (field names renamed to save on typing)
select t.* from teams t
inner join members me1 on t.m1 = me1.id
inner join members me2 on t.m2 = me2.id
where MATCH(me1.fname, me1.lname, me2.fname, me2.lname)
AGAINST('smith' IN BOOLEAN MODE);
Normalize your database.
In your case, this would mean having a table Team (team_id, name, whatever else), a table Member (member_id, first_name, last_name), and a table MemberToTeam (member_id, team_id). In other words, move the member1ID and member2ID into their own table.
Following this practice, apart from "improving" your database schema in the general sense, means that the query that bothers you will become trivial to write.
If you know the member_id:
SELECT team_id FROM MemberToTeam WHERE member_id = 1
If you search by first or last name:
SELECT mtt.team_id FROM Member m
LEFT JOIN MemberToTeam mtt ON m.member_id = mtt.member_id
WHERE m.first_name LIKE '%your search string here%' OR m.lastname LIKE '%your search string here%'