Getting error code 1054 when running sub query - mysql

I'm trying to get the user with oldest account created using this:
SELECT a.ID
, a.username
FROM users a
JOIN
( SELECT MAX(date_created)
FROM other_info
) b
ON a.ID = b.ID;
It's returning the following; `Error Code: 1054.
Unknown column 'b.ID' in 'on clause'`
I've looked though the [mysql-error-1054] tag and haven't been able to find a solution, I'm not even sure which part of the query is wrong.
Thanks.

To find the user with the first (oldest) date_created:
SELECT u.ID, a.username, b.date_created
FROM users a
INNER JOIN other_info b
ORDER BY b.date_created
LIMIT 1
BTW, instead of a, b etc, I'd rather chose table aliases that make sense, e.g. u for users.

SELECT a.ID
, a.username
, MAX(date_created)
FROM users a
INNER JOIN other_info b
ON a.ID = b.ID;

Try This :
SELECT a.ID, a.username
FROM users a INNER JOIN
(SELECT top 1 id,date_created FROM other_info order by date_created desc) b
ON a.ID = b.ID;

Related

Proper way to write a MySQL query that uses a derived column and multiple joins

This query is NOT legal syntax and I'm trying to understand what the efficient way of writing it is. This is what I have:
SELECT a.*, b.id, lapsed FROM
( SELECT DATEDIFF(CURDATE(), MAX(day)) AS lapsed FROM c ) AS x
FROM first_table a
INNER JOIN second_table b ON a.id = b.some_id
INNER JOIN third_table c ON c.user_id = a.user_id
WHERE a.some_col = 'm'
AND b.num >= lapsed
There's three tables being joined. Normally this would be trivial, but the problem is my last part of the WHERE clause, specifically b.num >= lapsed is doing a comparison on a derived value. Is there a correct way to write this?
Haven't tested this, but if the subquery is correct then this should work.
I also assumed that the 'c' in the example of the question is also referring to that third_table and not some table/view called c.
And the INNER JOIN to third_table was commented out, since it's mostly useless to INNER JOIN table/views when you don't use any fields of it. Well, it could be used to limit on records that are in that table, but most often it's just useless to do that.
SELECT a.*, b.id, x.lapsed
FROM first_table a
INNER JOIN second_table b ON a.id = b.some_id
--INNER JOIN third_table c ON c.user_id = a.user_id
LEFT JOIN (
SELECT DATEDIFF(CURDATE(), MAX(day)) AS lapsed
FROM third_table
) AS x ON (1=1)
WHERE a.some_col = 'm'
AND b.num >= x.lapsed;
Given the MAX() aggregate, it looks like you want the latest day value for each user_id value from third_table.
To get that, we can write a query like this:
SELECT c.user_id
, DATEDIFF(CURDATE(),MAX(c.day)) AS lapsed
FROM third_table c
GROUP BY c.user_id
You can use the resultset from this query as a rowsource in another query, by using that query as a inline view in place of a table reference. (MySQL refers to an inline view as a "derived table".)
We just wrap that query in parens, and use it in place of where we would normally find a table reference. The inline view (derived table) will need to be assigned an alias.
For example:
SELECT a.*
, b.id
, d.lapsed
FROM first_table a
JOIN second_table b
ON b.some_id = a.id
JOIN ( SELECT c.user_id
, DATEDIFF(CURDATE(),MAX(c.day)) AS lapsed
FROM third_table c
GROUP BY c.user_id
) d
ON d.user_id = a.user_id
WHERE a.some_col = 'm'
AND b.num > d.lapsed
A query similar to that should run. But whether that returns the resultset you expect to achieve, that really depends on what result you are attempting to return. Absent a specification (apart from some invalid query syntax), we're just guessing.

Incorrect id returned on LEFT JOIN in Mysql statement

I need to get the id and timestamps of table sellers and all other columns (without knowing the column names) from these results returned from this MySql statement:
SELECT * FROM sellers a
LEFT JOIN users b ON a.user_id = b.id
LEFT JOIN country_types c ON a.country_type_id = c.id
LEFT JOIN language_types d ON a.language_type_id = d.id
WHERE a.email=?
The seller id though is incorrectly set because users, country_types, and language_types all have a value id. How can I set seller_id and seller_timestamp? I tried this but it is incorrect:
SELECT a.id seller_id, a.timestamp seller_timestamp, * FROM sellers a ...
You want this:
SELECT a.id as seller_id, a.timestamp as seller_timestamp, a.*, b.*, c.*, d.*
FROM sellers a
LEFT JOIN users b ON a.user_id = b.id
LEFT JOIN country_types c ON a.country_type_id = c.id
LEFT JOIN language_types d ON a.language_type_id = d.id
WHERE a.email=?
Im not sure but try alias, for example:
a.id AS seller_id
and etc.
In joins you can't select other columns in this way:
SELECT a.id seller_id, a.timestamp seller_timestamp, * FROM sellers a...
You need to write required column names.

Multiple SELECT subqueries to the same table into one

There's a table message and a table sender, and I want to retrieve all "message information" associated to a specific id, along with the sender name and email. I have this query:
SELECT
a.id,
a.subject,
a.body,
a.sender_id,
(
SELECT b.name
FROM sender b
WHERE b.id = a.sender_id
LIMIT 1
) AS sender_name,
(
SELECT b.email
FROM sender b
WHERE b.id = a.sender_id
LIMIT 1
) AS sender_email,
a.sent_time
FROM message a
WHERE a.id = <id>
LIMIT 1;
It works, but it has to perform two different SELECT subqueries to the same table.
In this case (which is an extremely simplified example) it probably doesn't hurt the performance at all, but in a real-life scenario where a lot of fields have to be retrieved from an external table, the best way to do it is using a JOIN statement? Isn't it possible to have a SELECT subquery that retrieves many fields?
I'm using MySQL with MyISAM storage engine in case it matters.
Just join to the sender tables once in the FROM clause.
SELECT a.id,
a.subject,
a.body,
a.sender_id,
b.name,
b.email,
a.sent_time
FROM message a
INNER JOIN
sender b
ON b.id = a.sender_id
WHERE a.id = <id>
LIMIT 1;
Try this:
SELECT
a.id,
a.subject,
a.body,
a.sender_id,
b.name AS sender_name,
b.email AS sender_email,
a.sent_time
FROM message a, sender b
WHERE a.id = <id>
AND b.id = a.sender_id
LIMIT 1;
If you really don't want to use a join, you could use concat in your subquery CONCAT(b.name,";",b.email) and later explode the result on ; - but I'd go for join :D

How do I write a My(SQL) query that counts from multiple tables based on specific WHERE clause criteria

I have 5 tables: a, b, c, d and e.
Each table is joined by an INNER JOIN on the id field.
My query is working perfectly fine as it is but I need to enhance it to count the result so I can echo it to the screen. I have not been able to get the count working.
There are very specific fields I am querying:
state_nm
status
loc_type
These are all parameters I enter manually into the query like so:
$_POST["state_nm"] = 'AZ'; ... // and for all other below values..
SELECT *
FROM main_table AS a
INNER JOIN table_1 AS b ON a.id = b.id
INNER JOIN table_2 AS c ON b.id = c.id
INNER JOIN blm table_3 AS d ON c.id = d.id
INNER JOIN table_4 AS e ON d.id = e.id
WHERE a.trq != ''
AND b.state_nm = '".$_POST["state_nm"]."'
AND b.loc_type LIKE \ "%".$_ POST ["loc_type"]."%\"
AND b.STATUS = '".$_POST["status"]."'
GROUP BY b.NAME
ORDER BY c.county ASC;
not sure I get exactly what is your goal here.
anyway, using "select *" and group by in the same query is not recommended and in some databases will raise an error
what I would do is something like that:
select a.name, count(*) from (
SELECT * FROM main_table as a
INNER JOIN table_1 as b
ON a.id=b.id
INNER JOIN table_2 as c
ON b.id=c.id
INNER JOIN blm table_3 as d
ON c.id=d.id
INNER JOIN table_4 as e
ON d.id=e.id
WHERE a.trq != ''
AND b.state_nm = '".$_POST["state_nm"]."'
AND b.loc_type LIKE \"%".$_POST["loc_type"]."%\"
AND b.status = '".$_POST["status"]."'
)a
group by a.name
the basic idea is to add an outer query and use group by on it...
hopefully this solves your problem.
In place of
SELECT *
in your query, you could replace that with
SELECT COUNT(*)
That query should return the number of rows that would be in the resultset for the query using SELECT *. Pretty easy to test, and compare the results.
I think that answers the question you asked. If not, I didn't understand your question.
I didn't notice the GROUP BY in your query.
If you want to get a count of rows returned by that query, wrap it in outer query.
SELECT COUNT(1) FROM (
/* your query here */
) c
That will give you a count of rows returned by your query.

MySQL Question (joins)

I'm not that into MySQL joins, so maybe you could give me a hand. I've got the following tables:
Table a
Fields ID,name
Table b
Fields aID,cID,ID,found
Table c
Fields ID,name
The result I want to get is the following: I want all the records where b.found = 1. Of these records I don't want a.id or a.name, but I want the number of records that would have been returned if I would have wanted so. So if there are five records that have b.found = 1 and c.id = (for example) 3, then I want a returned value of 5, c.id and c.name.
Someone is able to do this?
Actually this is what I want to get from the database:
A list of all records in table C and a count of records in table B that has found = 1 and b.c_id = c.id
Table: a
Fields: ID, name
Table: b
Fields: aID, cID, found
Table: c
Fields: ID, name
SELECT c.ID, c.name, COUNT(1)
FROM b
JOIN c ON c.ID = b.cID AND b.found=1
GROUP BY c.ID
SELECT c.id, c.name, COUNT(*)
FROM c
INNER JOIN b
ON c.id = b.c_id
AND b.found = 1
GROUP BY c.id, c.name
SELECT COUNT(*), c.id, c.name
FROM a, b, c
WHERE a.id = b.a.id AND c.id = b.a.id AND b.found = 1 AND c.id = idThatIAmSearchingFor
Apologies if I didn't get the syntax exact, but I believe that's the basic structure you want. The COUNT function returns the number of rows found by the query.
Something like:
SELECT count(`c`.*),
`c`.`id`,
`c`.`name`
FROM `b`
JOIN `c`
ON `c`.`id` = `b`.`c_id`
WHERE `b.found` = 1
I think this would provide the required output -
select count(*), b.cID, c.name from b
inner join c on c.id=b.cID and b.found=1
group by b.cID
SELECT COUNT(*) AS Count, c.id, c.name
FROM b join a on a.id = b.a_id
WHERE b.found = 1
GROUP BY c.Id;
COUNT returns count of records in each group from GROUP BY.