MySQL Unknown column in 'on clause' :( - php

My query looks like
SELECT а.*, m.username, m.picture, m.picture_active
FROM questions_answer AS а
INNER JOIN members AS m ON а.poster_id=m.member_id
INNER JOIN questions AS q ON q.question_id=a.question_id
ORDER BY a.postdate DESC
I'm getting error:
Unknown column 'a.question_id' in 'on clause'
I don't know what is wrong, please help me with this.
Table questions is
CREATE TABLE IF NOT EXISTS `questions` (
`question_id` int(9) unsigned NOT NULL AUTO_INCREMENT,
`member_id` int(9) unsigned NOT NULL DEFAULT '0',
`question` text NOT NULL,
`postdate` int(10) unsigned NOT NULL DEFAULT '0',
`active` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`question_id`),
KEY `member_id` (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
and questions_answer is
CREATE TABLE IF NOT EXISTS `questions_answer` (
`answer_id` bigint(12) unsigned NOT NULL AUTO_INCREMENT,
`question_id` int(9) unsigned NOT NULL,
`poster_id` int(9) unsigned NOT NULL,
`body` text NOT NULL,
`postdate` int(9) unsigned NOT NULL,
PRIMARY KEY (`answer_id`),
KEY `question_id` (`question_id`),
KEY `poster_id` (`poster_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Your table questions_answer may not have the column question_id

It would seem you don't have a column a.question_id
Check your structure for that table.

There is not any column called question_id in the questions_answer table.

Funny thing, if I use this code, it works:
SELECT qa.*
FROM questions_answer qa
INNER JOIN questions q ON qa.question_id = q.question_id
ORDER BY qa.postdate DESC
SQL-fiddle
So, to apply this to your query:
SELECT qa.*, m.username, m.picture, m.picture_active
FROM questions_answer qa
INNER JOIN questions q ON qa.question_id = q.question_id
INNER JOIN members m ON qa.poster_id = m.member_id
ORDER BY qa.postdate DESC

Your questions_answer table alias a has some issues. It most probably isn't the letter a.
FROM questions_answer AS а
I was playing around with it and found an error once that noted Unknown table 'аa': As you can see, it might be a special character. A short search on net came up with letter Eth
I replaced the alias with character a and the query works fine.
SELECT a.*, m.username, m.picture, m.picture_active
FROM questions_answer AS a
INNER JOIN members AS m ON a.poster_id=m.member_id
INNER JOIN questions AS q ON q.question_id=a.question_id
ORDER BY a.postdate DESC
See example here Just copy paste your query there and try to run, it will complain because of alias character issue. You can even copy the alias from you line and replace all as with it, it will work as well.

Related

Multiple LEFT JOIN doesn't work on SUM()

So the idea is to get information from 3 tables:
R_Regle: rule table, basic info of the rule
C_Commentaire: the number of comments this rule has
I_Interet: The SUM of all upvotes and downvotes from one rule.
The structure of my I_Interet:
I_ID / I_Idregle / I_Idpseudo / I_Upvote / I_Downvote
Each row can only contain 1 upvote or 1 downvote.
so with this request:
SELECT R_Id, R_Date, R_Titre, R_Contenu, R_Etape, COUNT(C_Commentaire.C_IdRegle) AS CountComment, SUM(I_Interet.I_Up) AS Up ,SUM(I_Interet.I_Down) AS Down
FROM R_Regle
LEFT JOIN C_Commentaire ON C_Commentaire.C_IdRegle = R_Regle.R_Id
LEFT JOIN I_Interet ON I_Interet.I_IdRegle = R_Regle.R_Id
GROUP BY R_ID
I try to obtain all those information.
Problem is:
COUNT(C_Commentaire.C_IdRegle) AS CountComment
Gives me the count of all COMMENTS and UPVOTES/DOWNVOTES.
So if there are 4 comments and 3 downvotes, it will count it like that
$row['CountComment'] = 7;
But obviously, I don't want that. I want
$row['CountComment'] = 4;
Any ideas?
EDIT 1:
Here are the tables:
R_REGLE
CREATE TABLE `R_Regle` (
`R_Id` int(11) NOT NULL AUTO_INCREMENT,
`R_Auteur` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
`R_Date` date NOT NULL,
`R_Titre` varchar(150) CHARACTER SET latin1 NOT NULL,
`R_Contenu` text CHARACTER SET latin1 NOT NULL,
`R_Etape` int(11) NOT NULL DEFAULT '1' COMMENT '1 = discussion 2= VOTE',
PRIMARY KEY (`R_Id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
C_COMMENTAIRE
CREATE TABLE `C_Commentaire` (
`C_Id` int(11) NOT NULL AUTO_INCREMENT,
`C_Date` datetime NOT NULL,
`C_Pseudo` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
`C_Contenu` text COLLATE utf8_unicode_ci NOT NULL,
`C_IdRegle` int(11) NOT NULL,
PRIMARY KEY (`C_Id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
I_INTERET
CREATE TABLE `I_Interet` (
`I_Id` int(11) NOT NULL AUTO_INCREMENT,
`I_IdRegle` int(11) NOT NULL,
`I_Pseudo` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
`I_Up` tinyint(1) NOT NULL DEFAULT '0',
`I_Down` tinyint(1) DEFAULT '0',
PRIMARY KEY (`I_Id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
I can suggest using correlated query.. not sure if thats what you want since you didn't post any table structures its hard to know :
SELECT R_Id, R_Date, R_Titre, R_Contenu, R_Etape,
(select COUNT(*) from C_Commentaire where C_Commentaire.C_IdRegle = R_Regle.R_Id) AS CountComment,
SUM(I_Interet.I_Up) AS Up ,
SUM(I_Interet.I_Down) AS Down
FROM R_Regle
LEFT JOIN I_Interet ON I_Interet.I_IdRegle = R_Regle.R_Id
GROUP BY R_ID
Write your query as below:
SELECT R_Regle.R_Id, R_Regle.R_Date, R_Regle.R_Titre, R_Regle.R_Contenu, R_Regle.R_Etape,
COUNT(C_Commentaire.C_IdRegle) AS CommentCounts,
SUM(I_Interet.I_Up) AS Up,
SUM(I_Interet.I_Down) AS Down
FROM R_Regle
LEFT JOIN C_Commentaire ON R_Regle.R_Id = C_Commentaire.C_IdRegle
LEFT JOIN I_Interet ON R_Regle.R_Id = I_Interet.I_IdRegle
GROUP BY R_Regle.R_ID
In your query there are duplicate records arisen when you make a left join among the three tables.
The following query is one of few ways to achieve your desired result.
SELECT
t.*,
SUM(I_Interet.I_Up) AS Up,
SUM(I_Interet.I_Down) AS Down
FROM
(
SELECT
R_Id,
R_Date,
R_Titre,
R_Contenu,
R_Etape,
COUNT(c_commentaire.C_IdRegle) countComment
FROM
R_Regle LEFT JOIN C_Commentaire ON C_Commentaire.C_IdRegle = R_Regle.R_Id
GROUP BY R_Regle.R_Id ) t
LEFT JOIN I_Interet ON I_Interet.I_IdRegle = t.R_Id
GROUP BY t.R_Id

How to determine the ON clause for a dynamic query using PHP?

I am trying to write a script that will allow the user to select a list of fields to be displayed from different column/table in a database. This script will need be able to generate the full query and execute it.
I am able to select the field and add the proper where clause. However, I am being challenged on how to generate the ON clause which is part of the JOIN statement.
Here is what I have done so far.
First, I defined 3 tables like so
-- list of all tables available in the database
CREATE TABLE `entity_objects` (
`object_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`object_name` varchar(60) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
`object_description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`object_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- list of all tables available in the database
CREATE TABLE `entity_definitions` (
`entity_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`display_name` varchar(255) NOT NULL,
`entity_key` varchar(60) NOT NULL,
`entity_type` enum('lookup','Integer','text','datetime','date') CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
`object_id` int(11) unsigned NOT NULL,
PRIMARY KEY (`entity_id`),
KEY `object_id` (`object_id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
-- a list of the fields that are related to each other. For example entity 12 is a foreign key to entity 11.
CREATE TABLE `entity_relations` (
`relation_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`entity_a` int(11) unsigned NOT NULL,
`entity_b` int(11) unsigned NOT NULL,
`relation_type` enum('1:1','1:N') NOT NULL DEFAULT '1:1',
PRIMARY KEY (`relation_id`),
UNIQUE KEY `entity_a` (`entity_a`,`entity_b`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
To get a list of the relations that are available, I run this query
SELECT
CONCAT(oa.object_name, '.', ta.entity_key) AS entityA
, CONCAT(ob.object_name, '.', tb.entity_key) AS entityB
FROM entity_relations as r
INNER JOIN entity_definitions AS ta ON ta.entity_id = r.entity_a
INNER JOIN entity_definitions AS tb ON tb.entity_id = r.entity_b
INNER JOIN entity_objects AS oa ON oa.object_id = ta.object_id
INNER JOIN entity_objects AS ob ON ob.object_id = tb.object_id
I am having hard time trying to figure out how to generated the JOIN statement of the query. I am able to generate the SELECT ..... and the WHERE... but need help trying to generate the ON.... part of the query.
My final query should look something like this
SELECT
accounts.account_name
, accounts.industry_id
, accounts.primary_number_id
, accounts.person_id
, industries.industry_id
, industries.name
, contact_personal.first_name
, contact_personal.person_id
, account_phone_number.number_id
FROM accounts
LEFT JOIN industries ON industries.industry_id = accounts.industry_id
LEFT JOIN contact_personal ON contact_personal.person_id = accounts.person_id
LEFT JOIN account_phone_number ON account_phone_number.number_id = accounts.primary_number_id
WHERE industries.name = 'Marketing'
I created a SQL Fiddle with my MySQL code.
How can I define the ON clause of the join statement correctly?
It is completely unnecessary to create these tables, mysql can handle all of this for you so long as you are using the InnoDB storage engine by using foreign keys.
list all tables on current database
SHOW TABLES;
get list of columns on a given table
SELECT
*
FROM
information_schema.COLUMNS
WHERE
TABLE_SCHEMA = :schema
AND TABLE_NAME = :table;
get list of relationships between tables
SELECT
*
FROM
information_schema.TABLE_CONSTRAINTS tc
INNER JOIN
information_schema.INNODB_SYS_FOREIGN isf ON
isf.ID = concat(tc.CONSTRAINT_SCHEMA, '/', tc.CONSTRAINT_NAME)
INNER JOIN
information_schema.INNODB_SYS_FOREIGN_COLS isfc ON
isfc.ID = isf.ID
WHERE
tc.CONSTRAINT_SCHEMA = :schema
AND tc.TABLE_NAME = :table;

How do I select MySQL records based on results from a related table?

I have two tables in this scenario: members and team_members. The members table is pretty self explanatory. The team members table stores the member's team information if they are a member of the team. If there is no row in the team members table that has a member_id of a user, then they are not in a team. What I want to do is get all the users that are not members of a team. Should I use left join, inner join, outer join, or just join? What would this query look like?
CREATE TABLE IF NOT EXISTS `members` (
`member_id` int(15) NOT NULL AUTO_INCREMENT,
`group_id` int(15) NOT NULL,
`display_name` text NOT NULL,
`email_address` text NOT NULL,
`password` text NOT NULL,
`status` tinyint(1) NOT NULL,
`activation_code` varchar(16) NOT NULL,
`date_joined` text NOT NULL,
PRIMARY KEY (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `team_members` (
`team_member_id` int(15) NOT NULL AUTO_INCREMENT,
`member_id` int(15) NOT NULL,
`team_id` int(15) NOT NULL,
`date_joined` text NOT NULL,
`date_left` text NOT NULL,
`total_xp` int(15) NOT NULL,
PRIMARY KEY (`team_member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
There's several ways to write this query.
To me this is the easiest to read and understand:
select * from members where member_id not in (select member_id from team_members).
This is a really simple way to write it. If you decide you want everything you can quickly comment out the where clause:
select m.* from members m left outer join team_members tm on m.member_id = tm.member_id
where tm.member_id is null
This way doesn't seem very popular from the SQL I read but I think it's straightforward:
select m.* from members m where not exists
(select member_id from team_members tm where tm.member_id = m.member_id)
On the face of it, the below query is fine
SELECT members.member_id
FROM members
LEFT OUTER JOIN team_members
ON team_members.member_id = members.member_id
WHERE team_members.member_id IS NULL
This will do, but on reading your question again, you seem to have a date_left column and if you want only those members who have not yet left a team then
SELECT members.member_id
FROM members
LEFT OUTER JOIN (SELECT *
FROM team_members
WHERE team_members.date_left != '') CURRENT_TEAMS
ON CURRENT_TEAMS.member_id = members.member_id
WHERE CURRENT_TEAMS.member_id IS NULL
SQLFiddle example
http://www.sqlfiddle.com/#!2/46b25/6/0

how do I output the rowName based on a linking table?

I need to output A_Name, B_Name, and C_Name. from tableA, tableB, tableC. I have a linking table containing all the ID's of the above, e.g:
CREATE TABLE `tableLink` (
`tableLinkID` int(5) NOT NULL auto_increment,
`A_ID` int(11) NOT NULL,
`B_ID` int(5) NOT NULL,
`C_ID` int(5) NOT NULL,
PRIMARY KEY (`tableLinkID`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8 AUTO_INCREMENT=17 ;
My question: I need to know how to SELECT based on having C_ID, how to select and output A_ID's [A_Name], B_ID's [B_Name], and C_ID's [C_Name].
I hope this is clear enough.
(I have the C_ID in a variable)
Try using JOINs:
SELECT
tableA.A_Name,
tableB.B_Name,
tableC.C_Name
FROM tableLink
JOIN tableA ON tableLink.A_ID = A.ID
JOIN tableB ON tableLink.B_ID = B.ID
JOIN tableC ON tableLink.C_ID = C.ID
WHERE tableLink.C_ID = 42

How to show a list of recommendations based on friends of friends

I'm trying to do a mysql query to display a list of recommendations. The list of recommendations sorted by proximity of friends. I was able to sort the list based on the recommendations of friends, but I am having trouble sorting a list of recommendations based on friends of friends.
The following is the design of the tables:
/*Table structure for table `recommendation` */
CREATE TABLE `recommendation` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`kategori` varchar(255) NOT NULL,
`nama` varchar(255) NOT NULL,
`rating` set('1','2','3','4','5') NOT NULL,
`writer_id` varchar(255) NOT NULL,
`search_here` longtext NOT NULL,
`user_type` set('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `kategori` (`kategori`),
KEY `nama` (`nama`),
FULLTEXT KEY `search_here` (`search_here`)
)
ENGINE=MyISAM AUTO_INCREMENT=100174
DEFAULT CHARSET=latin1 COMMENT='recommendation table';
/*Table structure for table `user_relationship` */
DROP TABLE IF EXISTS `user_relationship`;
CREATE TABLE `user_relationship` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`me` varchar(255) NOT NULL,
`friend` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `me` (`me`)
)
ENGINE=MyISAM AUTO_INCREMENT=100982
DEFAULT CHARSET=latin1 COMMENT='user relationship table';
I apply the following query:
SELECT
a.id AS ids,
a.writer_id,
a.kategori,
a.rating,
b.me,
a.user_type
FROM
recommendation a
LEFT OUTER JOIN
user_relationship b
ON
a.writer_id = b.friend
AND
b.me='$USER_ID'
WHERE
MATCH(search_here) AGAINST('$SEARCH' IN BOOLEAN MODE)
ORDER BY
b.me DESC,
a.writer_id
The list of recommendations should shown in the following order: recommendations from friends, recommendations from friends of friends, and recommendations from the public.
anyone can help me?
thanks
EDIT:
I have tried create clone of user_relationship table named "user_friend_friend".
the "user_friend_friend" table design like this:
CREATE TABLE `user_friend_friend` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`friend` varchar(255) NOT NULL,
`friend2` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `friend` (`friend`)
)
ENGINE=MyISAM AUTO_INCREMENT=100982
DEFAULT CHARSET=latin1 COMMENT='user friend friend table';
I do following query:
SELECT
a.id AS ids,
a.writer_id,
a.kategori,
a.nama,
a.rating,
b.me, b.friend,
c.friend2 AS ff, a.user_type
FROM recommendation a
LEFT OUTER JOIN webref.user_relationship b
ON a.oleh = b.friend AND b.me='1010147270'
LEFT OUTER JOIN webref.user_friend_friend c
ON a.oleh = c.friend AND b.friend IS NULL
WHERE MATCH(search_here) AGAINST('$SEARCH' IN BOOLEAN MODE)
GROUP BY a.id
ORDER BY
b.me DESC,
user_type DESC,
rating DESC,
c.friend DESC,
a.writer_id
is there any more efficient solution?
A few performance tips:
- You should have an index on columns you are joining. For example it doesn't look like writer_id has an index.
- Using VARCHAR(256) as the type for a column you are joining is slow even if you use an index. It would be better to store the ids as integers. You could have a separate table that you stores the int -> varchar mapping that you query later.
But to do the friend of friend query, something like this should work:
SELECT
a.id AS ids,
a.writer_id,
a.kategori,
a.rating,
b.me,
a.user_type
FROM
recommendation a
LEFT OUTER JOIN
user_relationship b
ON
a.writer_id = b.friend
AND
b.me='$USER_ID'
LEFT OUTER JOIN
user_relationship c
ON
a.writer_id = c.friend
AND
c.me = b.friend

Categories