I'm working on a query that uses having to compare a sum of elements from a joined table to a value of a field from the "main" table.
Here's the gist of my query:
SELECT t1.id
FROM table1 AS t1
INNER JOIN table2 t2 ON t2.t1_id = t1.id -- AND OTHER CONDITIONS
-- WHERE more t1 conditions
GROUP BY t1.id
HAVING SUM(t2.amount) <> t1.total_amount
AND SUM(t2.amount) = (t1.component1+t1.component2+t1.component3+t1.component4);
It outputs : ERROR 1054 (42S22): Unknown column 't1.total_amount' in 'having clause'
Needless to say, the field exists in t1 and there were no typos (quadra-checked this, on the brink of insanity here).
I can't for the life of me figure out what's wrong here. I tried searching SO already and most of the having problems are due to people using HAVING instead of WHERE, but seeing as I'm using SUM(), I think this is the right way to go.
EDIT: Terje's answer was the most accurate, although I did manage to pull it off without using that syntax in (possibly the most stupid update sentence of all time) my update sentence, which was (stupid, do not try this at home unless everything else fails):
UPDATE t1
SET t1.total_amount =
(
SELECT SUM(t2.amount)
FROM table 2
--WHERE, AND
GROUP BY t1.id
HAVING SUM(t2.amount) <> t1.total_amount
AND SUM(t2.amount) = (t1.component1+t1.component2+t1.component3+t1.component4)
)
WHERE t1.id IN (same awful subquery as before, except selecting t2.t1_id)
--AND other conditions
;
P.S. : The end goal here is to use the same having conditions in an update sentence
Bunch of thanks in advance,
-Lauri
In order to compare to t1.total_amount you will have to add it to the GROUP BYclause, or to compare to e.g. min(total_amount). As you are grouping by t1.id it does not matter what aggregate function of total_amount you are using.
HAVING and GROUP BY only works on things you are actually selecting, unlike the WHERE and ORDER BY clauses. So you need to select total_amount, I'm afraid. Also, the syntax is '!=' for unequal in MySQL. (I stand corrected, '<>' is fine in MySQL.)
Think of WHERE and ORDER BY as your manipulation of the tables you are selecting from, and HAVING and GROUP BY as manipulating the data you now have.
Related
I have been going through many queries, but can't seem to find the right combination to get this to work. I get the error "You can't specify target table 't1' for update in FROM clause". I know MySQL doesn't like the subquery in the update statement and have read about wrapping it in other select statements, but can't seem to figure it out. Here is a stripped down query of what I am looking for:
UPDATE myTable t1 SET t1.num=concat(t1.num,'B') WHERE t1.num in ('1','2') and t1.expiry=(SELECT max(t2.expiry) from myTable t2 where t2.num=t1.num);
Basically trying to get the latest date (expiry) for each number (num) and change the number where applicable.
This should works :
UPDATE myTable t1, (SELECT num, max(expiry) expiry from myTable t2 group by num) t2
SET t1.num = concat(t1.num,'B')
WHERE t1.num in ('1','2')
and t1.expiry = t2.expiry
and t1.num = t2.num;
I've never done an inner join SQL statement before, so I don't even know if this is the right thing to use, but here's my situation.
Table 1 Columns: id, course_id, unit, lesson
Table 2 Columns: id, course_id
Ultimately, I want to count the number of id's in each unit in Table 1 that are also in Table 2.
So, even though it doesn't work, maybe something like....
$sql = "SELECT table1.unit, COUNT( id ) as count, table2.id, FROM table1, table2, WHERE course_id=$im_course_id GROUP BY unit";
I'm sure the syntax of what I'm wanting to do is a complete fail. Any ideas on fixing it?
SELECT unit, COUNT( t1.id ) as count
FROM table1 as t1 inner JOIN table2 as t2
ON t1.id = t2.id
GROUP BY unit
hope this helps.
If I understand what you want (maybe you could post an example input and output?):
SELECT unit, COUNT( id ) as count
FROM table1 as t1 JOIN table2 as t2
ON t1.id = t2.id
GROUP BY unit
Okay, so there are a few things going on here. First off, commas as joins are deprecated so they may not even be supported (depending on what you are using). You should probably switch to explicitly writing inner join
Now, whenever you have any sort of join, you also need on. You need to tell sql how it should match these two tables up. The on should come right after the join, like this:
Select *
From table1 inner join table2
on table1.id = table2.id
and table1.name = table2.name
You can join on as many things as you need by using and. This means that if the primary key of one table is several columns, you can easily create a one-to-one match between tables.
Lastly, you may be having issues because of other general syntax errors in your query. A comma is used to separate different pieces of information. So in your query,
SELECT table1.unit, COUNT( id ) as count, table2.id, FROM ...
The comma at the end of the select shouldn't be there. Instead this should read
SELECT table1.unit, COUNT( id ) as count, table2.id FROM ...
This is subtle, but the sql query cannot run with the extra comma.
Another issue is with the COUNT( id ) that you have. Sql doesn't know which id to count since table1 and table2 both have ids. So, you should use either count(table1.id) or count(table2.id)
I'm struggling with someone else's code. What might the WHERE clause do in the following (MySQL) statement?
SELECT * FROM t1, t2 WHERE t1.id = t2.id IN (1,2,3)
It's not providing the desired result in my case, but I'm trying to figure what the original author intended.
Can anyone provide an example of the use of a WHERE clause like this?
This condition starts from the right, evaluates t2.id IN (1,2,3), gets the result (0 or 1), and uses it for join with t1.id. All rows of t2 with id from the IN list are joined to the row in t1 that has id of one; all other rows of t2 are joined with the row in t1 that has id of zero. Here is a small demo on sqlfiddle.com: link.
It is hard to imagine that that was the intent of the author, however: I think a more likely check was for both items to be in the list, and also being equal to each other. The equality to each other is important, because it looks like the author wanted to join the two tables.
A more modern way of doing joins is with ANSI SQL syntax. Here is the equivalent of your query in ANSI SQL:
SELECT * FROM t1 JOIN t2 ON t1.id = t2.id IN (1,2,3)
I am trying to make a view of records in t1 where the source id from t1 is not in t2.
Like... "what records are not present in the other table?"
Do I need to include t2 in the FROM clause? Thanks
SELECT t1.fee_source_id, t1.company_name, t1.document
FROM t1
WHERE t1.fee_source_id NOT IN (
SELECT t1.fee_source_id
FROM t1 INNER JOIN t2 ON t1.fee_source_id = t2.fee_source
)
ORDER BY t1.aif_id DESC
You're looking to effect an anti-join, for which there are three possibilities in MySQL:
Using IN:
SELECT fee_source_id, company_name, document
FROM t1
WHERE fee_source_id NOT IN (SELECT fee_source FROM t2)
ORDER BY aif_id DESC
Using EXISTS:
SELECT fee_source_id, company_name, document
FROM t1
WHERE NOT EXISTS (
SELECT * FROM t2 WHERE t2.fee_source = t1.fee_source_id LIMIT 1
)
ORDER BY aif_id DESC
Using JOIN:
SELECT t1.fee_source_id, t1.company_name, t1.document
FROM t1 LEFT JOIN t2 ON t2.fee_source = t1.fee_source_id
WHERE t2.fee_source IS NULL
ORDER BY t1.aif_id DESC
According to #Quassnoi's analysis:
Summary
MySQL can optimize all three methods to do a sort of NESTED LOOPS ANTI JOIN.
It will take each value from t_left and look it up in the index on t_right.value. In case of an index hit or an index miss, the corresponding predicate will immediately return FALSE or TRUE, respectively, and the decision to return the row from t_left or not will be made immediately without examining other rows in t_right.
However, these three methods generate three different plans which are executed by three different pieces of code. The code that executes EXISTS predicate is about 30% less efficient than those that execute index_subquery and LEFT JOIN optimized to use Not exists method.
That’s why the best way to search for missing values in MySQL is using a LEFT JOIN / IS NULL or NOT IN rather than NOT EXISTS.
However, I'm not entirely sure how this analysis reconciles with the MySQL manual section on Optimizing Subqueries with EXISTS Strategy which (to my reading) suggests that the second approach above should be more efficient than the first.
Another option below (similar to anti-join)... Great answer above though. Thanks!
SELECT D1.deptno, D1.dname
FROM dept D1
MINUS
SELECT D2.deptno, D2.dname
FROM dept D2, emp E2
WHERE D2.deptno = E2.deptno
ORDER BY 1;
I'm having a problem getting a query to work, which I think should work. It's in the form
SELECT DISTINCT a, b, c FROM t1 WHERE NOT IN ( SELECT DISTINCT a,b,c FROM t2 ) AS alias
But mysql chokes where "IN (" starts. Does mysql support this syntax? If not, how can I go about getting these results? I want to find distinct tuples of (a,b,c) in table 1 that don't exist in table 2.
You should use not exists:
SELECT DISTINCT a, b, c FROM t1 WHERE NOT EXISTS (SELECT NULL FROM t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c)
Using NOT IN is not the best method to do this, even if you check only one key. The reason is that if you use NOT EXISTS the DBMS will only have to check indices if indices exist for the needed columns, where as for NOT IN it will have to read the actual data and create a full result set that subsequently needs to be checked.
Using a LEFT JOIN and then checking for NULL is also a bad idea, it will be painfully slow when the tables are big since the query needs to make the whole join, reading both tables fully and subsequently throw away a lot of it. Also, if the columns allow for NULL values checking for NULL will report false positives.
I had trouble figuring out the right way to execute this query, even with the answers provided; then I found the MySQL documentation reference I needed:
SELECT DISTINCT store_type
FROM stores
WHERE NOT EXISTS (SELECT * FROM cities_stores WHERE cities_stores.store_type = stores.store_type);
The trick I had to wrap my brain around was using the reference to the 'stores' table from the first query inside the subquery. Hope this helps (or helps others, since this is an old thread.)
From http://dev.mysql.com/doc/refman/5.0/en/exists-and-not-exists-subqueries.html
SELECT DISTINCT t1.* FROM t1 LEFT JOIN t2 ON (t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c) WHERE t2.a IS NULL
As far as I know, NOT IN can only be used for 1 field at a time. And the field has to be specified in between "WHERE" and "NOT IN".
(Edit:)
Try using a NOT EXISTS:
SELECT a, b, c
FROM t1
WHERE NOT EXISTS
(SELECT *
FROM t2
WHERE t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c)
In addition, an inner join on a, b, and c being equal should give you all non-DISTINCT tuples, while a LEFT JOIN with a WHERE IS NULL clause should give you the DISTINCT ones, as Charles mentioned below.
Well, I'm going to answer my own question, in spite of all the great advice others gave.
Here's the proper syntax for what I was trying to do.
SELECT DISTINCT a, b, c FROM t1 WHERE (a,b,c) NOT IN ( SELECT DISTINCT a,b,c FROM t2 )
Can't vouch for the efficiency of it, but the broader questions I was implicitly putting was "How do I express this thought in SQL", not "How do I get a particular result set". I know that's unfair to everyone who took a stab, sorry!
Need to add a column list after the WHERE clause and REMOVE the alias.
I tested this with a similar table and it is working.
SELECT DISTINCT a, b, c
FROM t1 WHERE (a,b,c)
NOT IN (SELECT DISTINCT a,b,c FROM t2)
Using the mysql world db:
-- dont include city 1, 2
SELECT DISTINCT id, name FROM city
WHERE (id, name)
NOT IN (SELECT id, name FROM city WHERE ID IN (1,2))