I am having trouble with the relational algebra and transformation into SQL of this rather complicated query:
I need to select all values from table A joined to table B where there are no matching records in table B, or there are matching records but the set of matching records do not have a field that contains one of 4 of a possible 8 total values.
Database is MySQL 5.0... using an InnoDB engine for the tables.
Select
a.*
from
a
left join
b
on
a.id=b.id
where
b.id is null
or
b.field1 not in ("value1","value2","value3","value4");
I'm not sure if there is any real performance improvement but one other way is:
SELECT
*
FROM
tableA
WHERE
id NOT IN ( SELECT id FROM tableB WHERE field1 NOT IN ("value1", "value2"));
Your requirements are a bit unclear. My 1st interpretation is that you only want the A columns, and never more than 1 instance of a given A row.
select * from A where not exists (
select B.id
from B
where B.id=A.id
and B.field in ('badVal1','badVal2','badVal3','badVal4')
)
My 2nd interpretation is you want all columns from (A outer joined to B), with perhaps more than one instance of an A row if there are multiple B rows, as long as not exists B row with forbidden value.
select * from A
left outer join B on A.id=B.id
where not exists (
select C.id
from B as C
where A.id=C.id
and C.field in ('badVal1','badVal2','badVal3','badVal4')
)
Both queries could be expressed using NOT IN instead of correlated NOT EXISTS. Its hard to know which would be faster without knowing the data.
Related
a, b are not directly related.
What does a,b have to do with the results?
select * from a,b where b.id in (1,2,3)
can you explain sql?
Since you haven't specified a relationship between a and b, this produces a cross product. It's equivalent to:
SELECT *
FROM a
CROSS JOIN b
WHERE b.id IN (1, 2, 3)
It will combine every row in a with the three selected rows from b. If a has 100 rows, the result will be 300 rows.
What you using is Multitable SELECT.
Multitable SELECT (M-SELECT) is similar to the join operation. You
select values from different tables, use WHERE clause to limit the
rows returned and send the resulting single table back to the
originator of the query.
The difference with M-SELECT is that it would return multiply tables
as the result set. For more deatils: https://dev.mysql.com/worklog/task/?id=358
In other word, you query is :
SELECT *
FROM a
CROSS JOIN b
WHERE b.id in (1,2,3)
I have a complex query which results in a table which includes a time column. There are always two rows with the same time:
The result also contains a value column. The value of two rows with the same time is always different.
I now want to extend the query to join the rows with the same time together. So my thought was to join the derived table like this:
SELECT A.time, A.value AS valueA, B.value as valueB FROM
(
OLD_QUERY
) AS A INNER JOIN A AS B ON
A.time=B.time AND
A.value <> B.value;
However, the JOIN A AS B part of the query does not work. A is not recognized as the derived table. MySQL is searching for a table A in the database and does not find it.
So the question is: How can I join a derived table?
You cannot join a single reference to a table (or subquery) to itself; a subquery must be repeated.
Example: You cannot even do
SELECT A.* FROM sometable AS A INNER JOIN A ...
The A after the INNER JOIN is invalid unless you actually have a real table called A.
You can insert the subquery's results into another table, and use that; but it cannot be a true TEMPORARY table, as those cannot be joined to themselves or referenced twice at all in almost any query. _By referenced twice, I mean joined, unioned, used as an "WHERE IN" subquery when it is already referenced in the FROM.
If nothing else distinguishes the rows, you can just use aggregation to get the two values:
select time, min(value), max(value)
from (<your query here>) a
group by time;
In MySQL 8+, you can use a cte:
with a as (
<your query here>
)
select a1.time, a1.value, a2.value
from a a1 join
a a2
on a1.time = a2.time and a1.value <> a2.value;
I want to get the SUM(column_a) from two different tables, and get their difference. I am using MySQL.
Table A's sum = 1234
Table B's sum = 4001
I'm not sure what to put in my ON clause:
SELECT
SUM(a.column1) AS table_a_sum,
SUM(b.column1) AS table_b_sum,
SUM(a.column1) - SUM(b.column1) AS difference
FROM table_a a
JOIN table_b b
ON ??????
A join without condition is a cross join. A cross join repeats each row for the left hand table for each row in the right hand table:
FROM table_a a
CROSS JOIN table_b b
Note that in MySQL, cross join / join / inner join are identical. So you could write:
FROM table_a a
JOIN table_b b
As long as you omit the on clause, this will work as a cross join.
If you'd like to sum two columns from two tables, a cross join would not work because it repeats rows. You'd get highly inflated numbers. For sums, a better approach uses subqueries, per #sgeddes answer.
Here's one option using subqueries -- there are several ways to do this:
SELECT
table_a_sum,
table_b_sum,
table_a_sum - table_b_sum AS difference
FROM
(SELECT SUM(column1) table_a_sum FROM table_a) a,
(SELECT SUM(column1) table_b_sum FROM table_b) b
You want to summarize first and then do the calculations:
select a.suma, b.sumb, a.suma - b.sumb
from (select sum(a.column1) as suma from tablea) a cross join
(select sum(b.column1) as sumb from tableb) b
Doing the cross join between the tables will generate a cartesian product that will mess up your sums.
How can I join table a and table b and get records for each? Not an actual join... not sure what this is called.
So if I have 3 records in a, and 5 records in b, I want 8 records back.
In a record for a, all b fields can be null. In a record for b, all a fields can be null.
edit: My tables have different fields.
Error Code: 1222. The used SELECT statements have a different number of columns
Like the others mentionned, you need an union
SELECT intColumn, varcharColumn, intColumn FROM a
UNION
SELECT intColumn, varcharColumn, 0 FROM b
but you must have the same number of columns and they must also have similar data types.
Here's a good tutorial about it
Also, if you want columns that are not in both tables, you can fill with nulls or constants.
You want a UNION:
SELECT something FROM a
UNION
SELECT something FROM b
Try this
SELECT * FROM a
LEFT JOIN b ON a.id1 = b.id2
UNION
SELECT * FROM a
RIGHT JOIN b ON a.id1 = b.id2
Just make sure, that A and B have different IDs
Edit: Working Fiddle
You can also use some other field other then id which are not same in two table
Edit: Updated fiddle
Got this bit of SQL as an update script, I've tried to add a work round to not being able to include the table to be updated as a clause in the statement so using sub queries, but struggling to get this to work.
Essientially I need update a vailue in table 1 with the summation of a field in table 2, but only where the two other fields match across a couple of tables and based on field6 the restriction is applied to the update clause.
UPDATE table1 W SET Field1=(SELECT field2 FROM
(SELECT A.id, B.field3, SUM(A.field2) AS field2
FROM table2 A, table3 B, table4 P
WHERE A.id=B.id AND P.field6=B.field6) B ) WHERE W.field6=B.field6
In the real world example, select the sum of points conceded in a rugby game when a rugby player has participated in the match. table 2 has the results (including the score) table 3 has the team sheets and table 1 and 4 are the same player table to be updated.
Hopefully this is clear enough and someone can point me in the right direction.
Tried the following:
UPDATE $WSLKEEP W, $WSLFIX A, $WSLFIXPLAY B
SET W.F_CONCEDED=SUM(A.F_AGAINST)
WHERE A.F_ID=B.F_GAMEID
AND B.F_NAME=W.F_NAME"
but now stuck with:
Invalid use of group function
Kind regards
It seems like your subquery should be grouping on field6 and exposing that column for inner join with table1. Here's how you do that in MySQL:
UPDATE table1 W
INNER JOIN (
SELECT B.field6, SUM(A.field2) AS field2
FROM table2 A, table3 B, table4 P
WHERE A.id=B.id AND P.field6=B.field6
GROUP BY B.field6
) B ON W.field6=B.field6
SET W.Field1 = B.Field2
And while we are at it, I would also recommend you to refrain from (ab)using comma joins in favour of explicit joins. The latter, however unusual at first after being long accustomed to a different syntax, can very soon become habitual and much more intuitive than the former. A great deal has been said on the topic, and some people may be holding quite strong opinions about comma joins. I say, comma joins can still have their share of use. However, when you are joining on a condition, the current ANSI syntax should be your choice.
Here's the above statement with the subquery transformed so as to use explicit joins:
UPDATE table1 W
INNER JOIN (
SELECT B.field6, SUM(A.field2) AS field2
FROM table2 A
INNER JOIN table3 B ON A.id = B.id
INNER JOIN table4 P ON P.field6 = B.field6
GROUP BY B.field6
) B ON W.field6 = B.field6
SET W.Field1 = B.Field2
For an update query like you have above, you are allowed to include multiple tables in the UPDATE clause, even if you aren't updating all of them. This will make sub-queries unnecessary and speed the execution quite a bit. For example, you can do something like this.
UPDATE table1 W, table2 A, table3 B, table4 P
SET W.Field1 = SUM(A.field2) ...
I'm unclear on the specifics of what you are trying to update exactly, but I just wanted to put out that you can often avoid sub-queries by using this kind of syntax.