SQL Inner Join issues - mysql

Currently I have the following command:
SELECT * FROM `clients`
WHERE `ID`=(SELECT `clientID`
FROM `websites`
WHERE `name` LIKE "%my name%")
LIMIT 0,20
I wish to use an inner join, because AFAIK that is how it should be handled.
I have no idea how to do it... Here is all I could think of:
SELECT *
FROM `clients`
WHERE INNER JOIN `websites` ON `websites`.`name` LIKE "%lead%"
LIMIT 0,20

SELECT c.* FROM `clients` c
INNER JOIN `websites` w ON w.clientID = c.ID
WHERE w.`name` LIKE '%lead%'
LIMIT 0,20

Related

Unknown column in 'where clause'. Neste subquery to improve perfomance of 'ORDER BY'

I have an a relationship a little odd but must be so:
SELECT COUNT(DISTINCT `t`.`id`)
FROM `radcliente` `t`
LEFT OUTER JOIN `radcliente_endereco_instalacao` `endereco_instalacao`
ON (`endereco_instalacao`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radcliente_telefone` `telefones`
ON (`telefones`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radcliente_email` `emails`
ON (`emails`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radmetodo_cobranca` `metodo_cobranca`
ON (`metodo_cobranca`.`cliente_id`=`t`.`id`) AND (metodo_cobranca.arquivo = 'nao')
LEFT OUTER JOIN `radacct` `ultimo_acct`
ON (`ultimo_acct`.`username`=`t`.`login`)
AND (ultimo_acct.radacctid = (
SELECT `radacctid` FROM
(SELECT radacctid
FROM `radacct` `fUzDDUDv`
WHERE username = t.login
) AS `fUzDDUDv` ORDER BY `radacctid` DESC LIMIT 1
)
)
WHERE (ultimo_acct.framedipaddress = '177.23.209.194')
Unknown column 't.login' in 'where clause'.
UPDATE:
Yes, that would solve a problem. I created this sub query why I'm using the Yii Framework, and the has_one relationships there is no limit, ie if one 'cliente' with millions of 'acct', the framework seeks all 'acct', to take only one this gives some GB of traffic and is very slow. To solve, I used the subquery seeking only the newest id to get the 'cliente' and the last 'acct' and make it work in Active Record, until then everything was fine, but the search was slow estremamente to seek a record took 40 seconds, then I discovered that the problem was in the 'ORDER BY' (radacctid is an index and tables are innodb), hence I did to solve the 'ORDER BY' outside the subquery, then resolvou, the problem that the subquery column the table 'cliente' (t.login) is like there, as I explained above.
I've tried also sort by another field, eg 'acctstarttime', and continued slow, only solved when I did it this way:
SELECT `radacctid` FROM
(SELECT radacctid
FROM `radacct` `fUzDDUDv`
WHERE username = t.login
) AS `fUzDDUDv` ORDER BY `radacctid` DESC LIMIT 1
UPDATE:
But the problem of INNER JOIN is that if there is no result for 'acct' does not return the 'cliente'.
UPDATE
The problem is not where the t.login but it is not recognized as existing within the subquery that I can not put 'out' if the order is not slow.
UPDATE
Read my comments? This is the situation. It really is only on the production server that has inserts and updates all the time.
I hope this one could help you in some way:
SELECT
COUNT(DISTINCT `t`.`id`)
FROM
`radcliente` `t`
LEFT OUTER JOIN `radcliente_endereco_instalacao` `endereco_instalacao`
ON (`endereco_instalacao`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radcliente_telefone` `telefones`
ON (`telefones`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radcliente_email` `emails`
ON (`emails`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radmetodo_cobranca` `metodo_cobranca`
ON (`metodo_cobranca`.`cliente_id`=`t`.`id`)
AND (metodo_cobranca.arquivo = 'nao')
INNER JOIN
(
SELECT `ultimo_acct_INNER`.*
FROM
`radacct` AS `ultimo_acct_INNER`
INNER JOIN
(
SELECT `fUzDDUDv`.`username` AS `maxID_username`, MAX(`radacctid`) AS `maxID_radacctid`
FROM `radacct` `fUzDDUDv`
GROUP BY `fUzDDUDv`.`username`
) AS `radacct_MAX_ID`
ON `ultimo_acct_INNER`.`username`= `radacct_MAX_ID`.`maxID_username`
AND `ultimo_acct_INNER`.`radacctid` = `radacct_MAX_ID`.`maxID_radacctid`
) AS `ultimo_acct`
ON (`ultimo_acct`.`username`=`t`.`login`)
WHERE
(ultimo_acct.framedipaddress = '177.23.209.194')
I replaced section:
(...)
LEFT OUTER JOIN `radacct` `ultimo_acct`
ON (`ultimo_acct`.`username`=`t`.`login`)
AND (ultimo_acct.radacctid = (
SELECT `radacctid` FROM
(SELECT radacctid
FROM `radacct` `fUzDDUDv`
WHERE username = t.login
) AS `fUzDDUDv` ORDER BY `radacctid` DESC LIMIT 1
)
)
(...)
with this one:
(...)
INNER JOIN
(
SELECT `ultimo_acct_INNER`.*
FROM
`radacct` AS `ultimo_acct_INNER`
INNER JOIN
(
SELECT `fUzDDUDv`.`username` AS `maxID_username`, MAX(`radacctid`) AS `maxID_radacctid`
FROM `radacct` `fUzDDUDv`
GROUP BY `fUzDDUDv`.`username`
) AS `radacct_MAX_ID`
ON `ultimo_acct_INNER`.`username`= `radacct_MAX_ID`.`maxID_username`
AND `ultimo_acct_INNER`.`radacctid` = `radacct_MAX_ID`.`maxID_radacctid`
) AS `ultimo_acct`
ON (`ultimo_acct`.`username`=`t`.`login`)
(...)
Could you try the following modification (for optimizing performance) ?
SELECT COUNT(DISTINCT `t`.`id`)
FROM
(
SELECT DISTINCT `t_sub`.`id`
FROM
`radcliente` `t_sub`
LEFT OUTER JOIN `radacct` `ultimo_acct`
ON (`ultimo_acct`.`username`=`t_sub`.`login`)
AND (ultimo_acct.radacctid =
(SELECT `fUzDDUDv`.radacctid
FROM `radacct` `fUzDDUDv`
WHERE `fUzDDUDv`.username = `t_sub`.login
ORDER BY `fUzDDUDv`.`radacctid` DESC LIMIT 1))
WHERE (ultimo_acct.framedipaddress = '177.23.209.194')
) AS `t`
LEFT OUTER JOIN `radcliente_endereco_instalacao` `endereco_instalacao`
ON (`endereco_instalacao`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radcliente_telefone` `telefones`
ON (`telefones`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radcliente_email` `emails`
ON (`emails`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radmetodo_cobranca` `metodo_cobranca`
ON (`metodo_cobranca`.`cliente_id`=`t`.`id`) AND (metodo_cobranca.arquivo = 'nao')
It preselects records joining first the clients table to the 'big' table 'radacct', selecting only the distinct set of 'right' client id-s and then joining this (relatively) small set to the rest of the tables in the topmost query
I think I understand now. I have no experience with Yii framework, so for know (taking into account your last comment) I can't think of something better than the following:
SELECT COUNT(DISTINCT `t`.`id`)
FROM `radcliente` `t`
LEFT OUTER JOIN `radcliente_endereco_instalacao` `endereco_instalacao`
ON (`endereco_instalacao`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radcliente_telefone` `telefones`
ON (`telefones`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radcliente_email` `emails`
ON (`emails`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radmetodo_cobranca` `metodo_cobranca`
ON (`metodo_cobranca`.`cliente_id`=`t`.`id`) AND (metodo_cobranca.arquivo = 'nao')
LEFT OUTER JOIN `radacct` `ultimo_acct`
ON (`ultimo_acct`.`username`=`t`.`login`)
AND (ultimo_acct.radacctid =
(SELECT `fUzDDUDv`.radacctid
FROM `radacct` `fUzDDUDv`
WHERE `fUzDDUDv`.username = t.login
ORDER BY `fUzDDUDv`.`radacctid` DESC LIMIT 1))
WHERE (ultimo_acct.framedipaddress = '177.23.209.194')
I hope someone could help get more precise answer to your needs.

SQL - Should I use a join?

I have the following sample query (MySQL):
SELECT * FROM `action`
WHERE `customer_id` IN
(SELECT `id` FROM `customer` WHERE `status`=1)
ORDER BY
action.date ASC
LIMIT 0, 10
I need to be able to ORDER BY the customer.status field. Do I accomplish this with a join?
status is a field on the customer table.
Edited Query:
SELECT * FROM `action`
ORDER BY
action.date ASC
LIMIT 0, 10
IMPORTANT!
I am parsing the return data via PHP. After running the revised query:
SELECT * FROM `action` a INNER JOIN `customer` c ON a.customer_id = c.id ORDER BY a.form_id ASC LIMIT 0, 10
My PHP code breaks...
This post helped me out.
My revised query looks like this:
SELECT
*, a.id AS lead_id, c.id AS customer_id
FROM
`action` a
INNER JOIN
`customer` c ON a.customer_id = c.id
ORDER BY c.status DESC
Thanks everyone!
UPDATE
Because I have some customer records without an action record, an INNER JOIN was not returning all relevant records. I use a JOIN now, and all results come back as expected.
SELECT *
FROM `action` a
INNER JOIN `customer` c on a.`customer_id` = c.`id`
WHERE c.`status` in (1, 4, 7, 8)
ORDER BY a.date, c.status
LIMIT 0, 10
You can do either:
SELECT * FROM `action` a
INNER JOIN `customer` c on c.id = a.customer_id
WHERE c.status = 1
ORDER BY a.date ASC, c.status
LIMIT 0, 10
Or:
SELECT * FROM `action` a
INNER JOIN `customer` c on (c.id = a.customer_id and c.status = 1)
ORDER BY a.date ASC, c.status
LIMIT 0, 10
EDIT:
It's probably worth pointing out there's no sense in ordering by c.status, as it will always be 1. However, I put that in there since it was brought up by others as well as mentioned in the OP. I would think it could be removed from both queries.
Yes, you may accomplish it with a join and may be faster:
SELECT * FROM `action` a join customer c on c.id=a.customer_id
where c.status=1
ORDER BY
a.date ASC
LIMIT 0, 10
Also, consider not using * and instead list the columns that you need. It will improve performance in case you need to select less than all columns and you won't get surprises in the future if the table changes.
SELECT * FROM `action` a
JOIN `customer` c on a.customer_id=c.id
WHERE c.status=1 order by a.date, c.status ASC
LIMIT 0, 10

Mysql joins problem

I use this query to select all articles :
SELECT articles.*,categories.category_name,users.username,tags.tag
FROM articles
LEFT JOIN `categories` ON articles.category_id = categories.category_id
LEFT JOIN `users` ON articles.author_id = users.user_id
LEFT JOIN `tags` ON articles.article_id = tags.article_id
ORDER BY articles.date_added DESC
I have an other table comments, and I want to count how many comments are there, where the article_id in that table = article_id in the articles table. I tried with COUNT, but then it returns only one result. How can I do that with one query?
You can use a subquery in the SELECT clause:
SELECT articles.*,categories.category_name,users.username,tags.tag, (SELECT count(*) FROM comments c WHERE c.article_id = articles.article_id) as comments_count
As arnaud576875 already stated, you can use a subquery to extract the summary data.
Two things I've noticed from your SQL that are not really a part of the question but still worth pointing out.
you can use a table alias to shorten your SQL and make it more readable.
So instead of
SELECT articles.*,categories.category_name,users.username,tags.tag
FROM articles
LEFT JOIN `categories` ON articles.category_id = categories.category_id
LEFT JOIN `users` ON articles.author_id = users.user_id
LEFT JOIN `tags` ON articles.article_id = tags.article_id
ORDER BY articles.date_added DESC
you'd code
SELECT a.*, c.category_name, u.username, t.tag
FROM articles a
LEFT JOIN `categories` c ON a.category_id = c.category_id
LEFT JOIN `users` u ON a.author_id = u.user_id
LEFT JOIN `tags` t ON a.article_id = t.article_id
ORDER BY a.date_added DESC
I would drop SELECT * and select only the fields that you actually are going to use. This also helps with readability of your code.

Join: three tables and a or condition

I think I should know this somehow, especially after reading a lot of questions and answers regarding "The condition must go into the ON clause, not in the WHERE clause". However, I am still lost.
I have three tables, and I join them normally with LEFT (OUTER) joins. The joined tables looks like this (retty standard):
task_id task_questions_taskId taskQuestions_questionId question_id
1 1 5 5
1 1 8 8
2 2 8 8
SELECT `t`.`id` AS `task_id` ,
`task_questions`.`taskId` AS `task_questions_taskId` ,
`task_questions`.`questionId` AS `task_questions_questionId` ,
questions.id AS question_id
FROM `task` `t`
LEFT OUTER JOIN `task_questions` `task_questions`
ON ( `task_questions`.`taskId` = `t`.`id` )
LEFT OUTER JOIN `question` `questions`
ON ( `task_questions`.`questionId` = `questions`.`id` )
This is the standard query to get all the records. (It's taken from Yii; I actually want to to this with Active Record, but can't even get plain SQL right).
And now I want to get ONLY those tasks that have the question_id 2 AND 8 (e.g)
So if a task has not both of those question.ids, I don't want it in the result set.
In this case, the task could have other question_ids, too. Although it would be interesting to see how the query would look if it should return only those that have exactly those 2 (or any other set).
It's easy to get all the tasks that have one question, with WHERE question.id = 2,
but an AND in the WHERE clause leads to an empty result.
The WHERE clause can only apply conditions to one row at a time. But your questions of different id occur on different rows. How to solve this? Join both rows onto one row using a self-join.
Here's an example:
SELECT t.`id` AS `task_id`, ...
FROM `task` AS t
INNER JOIN `task_questions` AS tq2 ON ( tq2.`taskId` = t.`id` )
INNER JOIN `questions` AS q2 ON ( tq2.`questionId` = q2.`id` )
INNER JOIN `task_questions` AS tq8 ON ( tq8.`taskId` = t.`id` )
INNER JOIN `questions` AS q8 ON ( tq8.`questionId` = q8.`id` )
WHERE q2.`id` = 2 AND q8.`id` = 8
Another solution is to find the tasks that have questions 2 OR 8, and then use GROUP BY and HAVING to filter by groups that have exactly two of those.
SELECT t.`id` AS `task_id`, ...
FROM `task` AS t
INNER JOIN `task_questions` AS tq ON ( tq.`taskId` = t.`id` )
INNER JOIN `questions` AS q ON ( tq.`questionId` = q.`id` )
WHERE tq.`questionId` IN (2, 8)
GROUP BY t.`id`
HAVING COUNT(DISTINCT q.`id`) = 2
you can do this even with out using and
... where question.id IN (2,8)
Use IN:
SELECT `t`.`id` AS `task_id` ,
`task_questions`.`taskId` AS `task_questions_taskId` ,
`task_questions`.`questionId` AS `task_questions_questionId` ,
questions.id AS question_id
FROM `task` `t`
LEFT OUTER JOIN `task_questions` `task_questions`
ON ( `task_questions`.`taskId` = `t`.`id`)
LEFT OUTER JOIN `question` `questions`
ON ( `task_questions`.`questionId` = `questions`.`id` )
WHERE `task_questions`.`questionId` IN (2, 8)
This should do it
SELECT `t`.`id` AS `task_id` ,
`task_questions`.`taskId` AS `task_questions_taskId` ,
`task_questions`.`questionId` AS `task_questions_questionId` ,
questions.id AS question_id
FROM `task` `t`
LEFT OUTER JOIN `task_questions` `task_questions`
ON ( `task_questions`.`taskId` = `t`.`id` )
LEFT OUTER JOIN `question` `questions`
ON ( `task_questions`.`questionId` = `questions`.`id` )
WHERE questions.id in (2,8)
You're not looking for AND, you're looking for OR, or an IN:
WHERE `questions`.`id` IN (2,8) -- grab everything in the parens.
Or
WHERE `questions`.`id` = 2 OR -- grab each item individually
`questions`.`id` = 8
If you use AND that would mean the ID would have to be 8 and 2 at the same time. Bad deal.

Inner Join in ON Clause

I have a MySQL query that is trying to get all the Pages that contain Data like 'word%'. I have a many-to-many table called Pages2Data. It seems that to do this, I need to have an inner join connecting the Pages to the Pages2Data table, and then another inner join connecting Pages2Data to Data.
The following did not work, because the nested SELECT clause can return more than one row. I'm not sure how to fix it though:
SELECT * FROM `Pages`
INNER JOIN `Pages2Data` ON
(`Pages2Data`.`DataID`=(SELECT `DataID` FROM `Data` WHERE `DataWord` LIKE 'word%'))
AND `Pages`.`PageID`=`Pages2Data`.`PageID`;
SELECT * FROM `Pages`
INNER JOIN `Pages2Data`
ON `Pages`.`PageID`=`Pages2Data`.`PageID`
INNER JOIN `Data` ON `Data`.`DataID`= `Pages2Data`.`DataID`
WHERE `DataWord` LIKE 'word%';
First the problems with your query:
the join condition should be next to the ON clause
there is no WHERE clause in the outer most query
Fixed query:
SELECT * FROM `Pages`
INNER JOIN `Pages2Data` ON `Pages`.`PageID`=`Pages2Data`.`PageID`
WHERE `Pages2Data`.`DataID`= (SELECT `DataID` FROM `Data` WHERE `DataWord` LIKE 'word%');
Alternative query:
SELECT `PG`.*
FROM `Pages` `PG`
INNER JOIN `Pages2Data` `PD` ON `PD`.`PageID` = `PG`.`PageID`
INNER JOIN `Data` `DA` ON `PD`.`DataID` = `DA`.`DataID`
WHERE `DA`.`DataWord` LIKE 'word%';
try this
SELECT * FROM `Pages` p, `Pages2Data` p2d, `Data` d
WHERE p.`PageID` = p2d.`PageID`
AND p2d.`DataID` = d.`DataID`
AND `DataWord` LIKE 'word%'
You can check 'Like' in where clause.
SELECT * FROM
`Pages`
INNER JOIN
`Pages2Data` ON (`Pages`.`PageID`=`Pages2Data`.`PageID`)
WHERE
`DataWord` LIKE 'word%'
SELECT *
FROM Pages
INNER JOIN Pages2Data
ON Pages.PageID = Pages2Data.PageID
INNER JOIN Data
ON Pages2Data.DataID = Data.DataID
WHERE DataWord LIKE 'word%'