Mysqli - #1052 - Column 'id' in field list is ambiguous - mysql

SELECT id,firstName,lastName, SUM(qty*price)
FROM orders,menu,customers
WHERE menu.id = orders.id_menu
AND orders.id_customer = customers.id
GROUP BY (id,firstName,lastName)
ORDER BY (SUM(qty*price)) LIMIT 1;
1052 - Column 'id' in field list is ambiguous
i need to get the best customer

Some simple rules when writing SQL:
Never use commas in the FROM clause.
Always use explicit, proper JOIN syntax.
Always alias your tables with abbreviations.
Always qualify your column references.
Your resulting queries are more likely to work the first time:
SELECT c.id, c.firstName, c.lastName, SUM(o.qty * m.price)
FROM orders o JOIN
menu m
ON m.id = o.id_menu JOIN
customers c
ON c.id = o.id_customer
GROUP BY c.id, c.firstName, c.lastName
ORDER BY SUM(o.qty * m.price)
LIMIT 1;

Change the query to this
SELECT customers.id,firstName,lastName, SUM(qty*price) FROM orders,menu,customers WHERE menu.id = orders.id_menu AND orders.id_customer = customers.id GROUP BY (customers.id,firstName,lastName) ORDER BY (SUM(qty*price)) LIMIT 1;
I believe all these tables have column called 'id' and you need to specify which one you need otherwise it will give you this message.

You have many columns as name 'id' in different tables so mysql can not know where is it from (menu.id vs customer.id).

change to:
SELECT id,firstName,lastName, SUM(qty*price)
FROM orders,menu,customers
WHERE menu.id = orders.id_menu
AND orders.id_customer = customers.id
GROUP BY (orders.id,firstName,lastName)
ORDER BY (SUM(qty*price)) LIMIT 1;
you want orders.id as those will be associated with qty and price

Related

MySQL Error: 1111 (Invalid use of group function) [duplicate]

This question already has an answer here:
ERROR 1111 (HY000): Invalid use of group function
(1 answer)
Closed 1 year ago.
I'm not yet good at MySQL. Please check my sql below and help me understand where I went wrong with it. All I need is just one record for the order.id and the returned record must be the one whose shipped date is the latest.
Database error: Invalid SQL: SELECT orders.id, orders.customer_fk FROM orders INNER JOIN order_details ON order_details.order_fk=orders.id WHERE orders.payment_method IN ('AS','AC') AND ((orders.order_status='SHP' AND order_details.item_status='SHP' AND MAX(order_details.shipped_date) <= '2021-08-07') OR (orders.order_status='CAN' AND orders.order_date <= '2021-08-07 09:56:18')) AND orders.pii_status <> '1'GROUP BY orders.id
MySQL Error: 1111 (Invalid use of group function)
Instead of using MAX alone try to use a subselect
If you don't want the mad for every order.id then you need to add a inner join
SELECT
orders.id, orders.customer_fk
FROM
orders
INNER JOIN
order_details ON order_details.order_fk = orders.id
WHERE
orders.payment_method IN ('AS' , 'AC')
AND ((orders.order_status = 'SHP'
AND order_details.item_status = 'SHP'
AND (SELECT MAX(shipped_date) FROM order_details WHERE order_fk = orders.id) <= '2021-08-07')
OR (orders.order_status = 'CAN'
AND orders.order_date <= '2021-08-07 09:56:18'))
AND orders.pii_status <> '1'
GROUP BY orders.id
To explain it somewhat further
SELECT MAX(shipped_date) FROM order_details WHERE order_fk = orders.id) <= '2021-08-07'
Return true or false for every Order.id as it checks for every row in the outer select what the maximum date is and then checks it against the date.
After selecting all rows you GROUP BY(which i still don't get as you have no aggregation function it) comes for every order.id.
Maybe you should try a DISTINCT
You select both orders.id and orders.customer_fk, but you group by orders.id only. When using group by in SQL, all other columns not present in the group by clause must be aggregate functions, since for example in this current case you group the results by the order id, meaning there can be only one row per unique order id among the results.
And something has to happen with the list of values of the other column that all belong to this one grouped order id, this is where the aggregations come in. If it is a number you can calculate the MIN/MAX/AVG etc. of these, but the simplest aggregate is to just count the matching results.
So if you wanted your query to return the number of order.customer_fk for each unique order.id, just add SELECT orders.id, COUNT(orders.customer_fk).
Otherwise, if you didn't intend to group your results, you can remove the GROUP BY clause, or replace it with an ORDER BY.
If you want to filter using aggregation functions use having. However, I'm guessing that you just want to filter by the date:
SELECT o.id, o.customer_fk
FROM orders o INNER JOIN
order_details od
ON od.order_fk= o.id
WHERE o.payment_method IN ('AS','AC') AND
((o.order_status = 'SHP' AND od.item_status='SHP' AND od.shipped_date <= '2021-08-07') OR
(o.order_status = 'CAN' AND o.order_date <= '2021-08-07 09:56:18')
) AND
o.pii_status <> '1'
GROUP BY o.id

MYSQL: Error Code: 1054. Unknown column in 'where clause'

I'm trying to pass a column from the outer query as shown below to the inner query in the WHERE clause and MySQL does not like it. I'm unsure how to rewrite this query to make it work.
The error message I am getting is Unknown column 'y.DateShipped' in where clause
What I am trying to do is to join to the row in the inner table with an EffectiveDate that is less than the DateShipped and also is the max EffectiveDate in the inner join (there can be multiple rows for the same group by with different EffectiveDate(s))
I would love to know how to get this working or rewrite it so that it will work. I am using MySQL 5.6, so I don't have window functions available otherwise I think that could work.
select
x.id,
y.id,
y.DateShipped
from Shipment y inner join
(select id, SourceId, DestinationId, SourcePPFContractId, EffectiveDate
from Relationship where EffectiveDate <= y.DateShipped order by
EffectiveDate desc limit 1) x
on x.DestinationId = y.DestinationCustomerId
and x.SourceId = y.OriginCustomerId
and x.SourcePPFContractId = y.OriginContractId;
The inner select (from Relationship) is executed first and then merged with the first select. That's why it doesn't work. You should move the DateShipped to the where clause of the first select:
select
x.id,
y.id,
y.DateShipped
from Shipment y inner join
(select id, SourceId, DestinationId, SourcePPFContractId, EffectiveDate
from Relationship order by
EffectiveDate desc limit 1) x
on x.DestinationId = y.DestinationCustomerId
and x.SourceId = y.OriginCustomerId
and x.SourcePPFContractId = y.OriginContractId
and x.EffectiveDate <= y.DateShipped;
You are attempting something called a lateral join -- and MySQL does not support those. Because you want only one column, you can use a correlated subquery:
select (select r.id
from Relationship r
where r.DestinationId = s.DestinationCustomerId and
r.SourceId = s.OriginCustomerId and
r.SourcePPFContractId = s.OriginContractId and
r.EffectiveDate <= s.DateShipped
order by r.EffectiveDate desc
limit 1
) as x_id,
s.id, s.DateShipped
from Shipment s ;
Note that I also changed the table aliases to be abbreviations for the table names -- so the query is easier to read.
you would need to list the shipment table in the sub query to be able to call it properly try:
select
x.id,
y.id,
y.DateShipped
from Shipment y inner join
(select id, SourceId, DestinationId, SourcePPFContractId, EffectiveDate
from Relationship, Shipment where EffectiveDate <= Shipment.DateShipped order by
EffectiveDate desc limit 1) x
on x.DestinationId = y.DestinationCustomerId
and x.SourceId = y.OriginCustomerId
and x.SourcePPFContractId = y.OriginContractId;

MySQL Count as {name} and WHERE {name} = X, Unknown column

I am trying to filter results based on the name assigned on count() and get this:
Unknown column 'total_submissions' in 'where clause'
SELECT SQL_CALC_FOUND_ROWS patient.*,count(patient_data.id) as total_submissions
FROM patient
LEFT JOIN patient_data ON (patient_data.patient_id = patient.id AND patient_data.date_finished IS NOT NULL)
WHERE patient.doc_id = 2 AND total_submissions = 5
GROUP BY patient.id
ORDER BY patient.id DESC
LIMIT 0,40
After more research I did find out about not being able to use a column alias in the WHERE but I am unsure how to execute this query then. I assume it's possible but how would I be able to filter the results based on the count() calculation of the query?
total_submissions is a column alias and the result of an aggregation function. You need to do that check in a havingclause:
SELECT SQL_CALC_FOUND_ROWS p.*, count(pd.id) as total_submissions
FROM patient p LEFT JOIN
patient_data pd
ON pd.patient_id = p.id AND pd.date_finished IS NOT NULL
WHERE p.doc_id = 2
GROUP BY p.id
HAVING total_submissions = 5
ORDER BY p.id DESC
LIMIT 0, 40;
Notes:
Table aliases make the query easier to write and to read.
The condition on doc_id should still be in the WHERE clause.
You can't use column alias in where clause because the precedence in sql evaluation don't let the db engine know the alias name when evaluate the where clause
First is evaluated the FROM clase then the WHERE clause and after the SELECT cluase ..
In your case you have an aggregation function related to yu alias and this can be evaluated only after the group by is performed, pratically at the end of query process
for this reason there is a proper filter based on HAVING that work on the result of the aggreated query
SELECT SQL_CALC_FOUND_ROWS patient.*, count(patient_data.id) as total_submissions
FROM patient
LEFT JOIN patient_data ON (patient_data.patient_id = patient.id AND patient_data.date_finished IS NOT NULL)
WHERE patient.doc_id = 2
GROUP BY patient.id
HAVING total_submissions = 0
ORDER BY patient.id DESC
LIMIT 0,40

Left Join - Unknown Column?

Can you assist me with my query? I keep receiving an error that states "Error Code: 1054. Unknown column 'cdata.customerid' in 'on clause'"
If I want to attach the left join data where the customer id's match from customerdata table and order table, how can I achieve this? I must not understand at what point SQL allows data to become accessible by different parts of the query.
select
cdata.customerid,
cdata.affiliate,
cdata.firstname,
cdata.address1,
cdata.address2,
cdata.city,
cdata.state,
cdata.postalcode,
cdata.emailaddress,
cdata.active
from customerdata cdata, order a
left join
(select
a.transactiondate,
sum(a.TransactionAmount),
a.id
from order a
group by a.id)
txns on a.id = cdata.customerid
where cdata.active = "A";
In on clause you have to specify fields that belong to the tables which are taking part in join clause. So, if you are joining cdata with the txns subquery, you have to probably join on txns.id and cdata.customerid. You probably also wanted to get your sum out of your subquery, so you have to include this field in your main SELECT clause. And you probably have to specify transactiondate field in your group by clause, at least this is necessary for ORACLE DB, I am not sure if this is the case for MySQL:
select
cdata.customerid,
cdata.affiliate,
cdata.firstname,
cdata.address1,
cdata.address2,
cdata.city,
cdata.state,
cdata.postalcode,
cdata.emailaddress,
cdata.active,
txns.tsum,
txns.transactiondate
from customerdata cdata
left join
(select
a.transactiondate,
sum(a.TransactionAmount) tsum,
a.id
from order a
group by a.id, a.transactiondate) txns
on txns.id = cdata.customerid
where cdata.active = "A";
The JOIN references the table 'order' and the table 'txns', 'cdata' is not involved here, so within the context of the join cdata.customerid does not exist.

SQL GROUP BY multiple columns?

I have one table and I need to group the entries by two different columns
here is my code
SELECT *
FROM (
SELECT max(user_msg.id) AS mid, max(user_msg.timestamp) AS tsp, user_msg.text,
usr1.id AS u1_id, usr1.nickname AS u1_nickname, usr1.avatar AS u1_avatar, usr1.avatar_art AS u1_avatar_art,
usr2.id AS u2_id, usr2.nickname AS u2_nickname, usr2.avatar AS u2_avatar, usr2.avatar_art AS u2_avatar_art,
COUNT(user_msg.id) AS cnt
FROM user_msg
join user using (client_id)
LEFT JOIN user AS usr1 ON user_msg.from_id=usr1.id
LEFT JOIN user AS usr2 ON user_msg.to_id=usr2.id
WHERE user_msg.to_id = '".$user_id."' AND to_delete='0' OR user_msg.from_id = '".$user_id."' AND to_delete='0'
group by u1_id, u2_id ORDER by tsp DESC
) c
it should be something like group by u1_id AND u2_id
You need to use the original column names, not the aliases. They aren't processed yet (well, in SQL Server they aren't: not sure of MYSQL).
...
WHERE user_msg.to_id = '".$user_id."' AND to_delete='0' OR user_msg.from_id = '".$user_id."' AND to_delete='0'
group by usr1.id, usr2.id
ORDER by tsp DESC
...
Edit: MySQL allows aliases in the GROUP BY
So, I suspect the GROUP BY is wrong and ambiguous and need to be like the standard SQL underneath. With or without aliases
Like this question: SQL Query not showing expected result
[end edit]
Note, to make this standard SQL (or run on any other RDBMS), you need to use all the columns in the GROUP BY that are not in an aggregate:
SELECT
max(user_msg.id) AS mid,
max(user_msg.timestamp) AS tsp,
user_msg.text,
usr1.id AS u1_id, usr1.nickname AS u1_nickname, usr1.avatar AS u1_avatar, usr1.avatar_art AS u1_avatar_art,
usr2.id AS u2_id, usr2.nickname AS u2_nickname, usr2.avatar AS u2_avatar, usr2.avatar_art AS u2_avatar_art,
COUNT(user_msg.id) AS cnt
FROM user_msg
join user using (client_id)
LEFT JOIN user AS usr1 ON user_msg.from_id=usr1.id
LEFT JOIN user AS usr2 ON user_msg.to_id=usr2.id
WHERE user_msg.to_id = '".$user_id."' AND to_delete='0' OR user_msg.from_id = '".$user_id."' AND to_delete='0'
GROUP BY
user_msg.text, usr1.id, usr1.nickname, usr1.avatar, usr2.avatar_art,
usr2.id, usr2.nickname, usr2.avatar, usr1.avatar_art
ORDER by tsp DESC