Is it a bug? Or an error? Or a wrong query? - mysql

I have a problem about query in mysql. I made 2 tables, tables1 and table 2. In table1 there is 2 rows data, its same in table2 where it have 2 rows data, and every table have 3 fields. In this case, I want to make view and this a query :
create view point as select table2.field2 from table1, table2;
I think it will show data in table2 where it have 2 rows data. But the result is showing 4 rows data where every 2 rows is a same data.
When im trying delete 1 row in table1, its mean delete 1 data, and i try input the query like above. The result is correct, its showing 2 rows data in table2. Why it correct when in table1 have 1 row data, and didnt when table1 have 2 rows data. Please how to resolve it? Or its my wrong query.

You are using implicit cross join between these two tables.
Let's say table1 has m rows and table2 has n rows.
Then
SELECT * FROM table1,table2 will return m*n rows.
The above query is equivalent to this:
SELECT * FROM table1 CROSS JOIN table2.
If you want to get all rows from table1 and table2 keeping in mind that I don't want duplicates then you need to use UNION.
So, you might be looking for this query:
CREATE VIEW point AS
SELECT table2.field2 from table2
UNION
SELECT table1.field2 from table1
Note:
If you want to allow duplicate values in your final result set then use UNION ALL instead of UNION like below:
CREATE VIEW point AS
SELECT table2.field2 from table2
UNION ALL
SELECT table1.field2 from table1

Related

MySQL. Subtract data from table2 in table1

Simple question, but I don't get the way to acomplish it.
Table 1.
ID Quantity
1 4
2 5
3 2
Table 2
ID Quantity
2 1
3 2
I want the query to obtain the following result:
Table result
ID Quantity
1 4
2 4
I have been looking for something related with MINUS operator or NOT IN, but the thing is I want to substract the quantity in the same query.
EDIT: Table 1 is always bigger than Table 2. Table 2 can't contain id's that are not present in table 1.
I hope the example clarifies the question.
Regards!!
Sounds like a classic use-case of a join:
SELECT table1.value - COALESCE(table2.value, 0) AS value
FROM table1
LEFT OUTER JOIN table2
ON table1.id = table2.id
WHERE table1.value != table2.value
-- insert order by clauses/etc if needed
This will compute the values of table2's value minus table1's. You can get a good overview of different joins here. This uses a left join, which will only include results where there are ids in both table1 and table2 that match, and then uses COALESCE to turn the null/non-match from table2 into a 0.
The last statement's purpose is to finally remove results which equate to 0, so this would not include the (3, 0) result.
You can also use this join to create a view of the output, which has advantages like caching and speeding up your lookups.
SELECT table1.value - IFNULL(table2.value, 0) AS value
FROM table1
LEFT JOIN table2
ON table1.ID = table2.ID
WHERE table1.value > table2.value
To walk you through the above query. You use a LEFT JOIN here to combine your two tables. LEFT JOIN is specifically used since not all table 1 IDs all guaranteed to appear in table 2, but you still want to output these results. You use the ID in your ON condition since that is how you are matching the tables. You need to include the IFNULL statement since table 1 IDs with no matching table 2 IDs will result in NULL table 2 values for that joined row. You then subtract these two values to obtain your result. The WHERE clause here will remove rows which would have returned a value equal to or less than zero.
Use this SELECT statement:
SELECT T1.ID, T1.Quantity - COALESCE(T2.Quantity, 0) AS Quantity
FROM T1 LEFT JOIN T2 ON T1.ID = T2.ID
ORDER BY T1.ID;

MySql inner join of 2 tables

Im sure Im missing something vital here so any advices are welcome. I have one base table lets call it Content_1 and two additional tables called Content_2 and Content_3. What Im trying to do is get all results from table_2 matching the id from table 1 and to add to this result set all results from table_3 which also match the id coming from table_1. Basically to have an OR condition in the final results - return everything from table 2 matching the id from table 1 OR return everything from table 3 matching the id from table 1. However I see that no results are returned so my guess is that we make the first join and then second join is applied to the result set returned after the first join, not on the initial join.
SELECT * FROM Content_1
JOIN Content_2 ON Content_1.id = Content_2.id
JOIN Content_3 ON Content_1.id = Content_3.id
You probably want UNION instead of joining all 3 tables.
SELECT Col1, Col2
FROM Content_1
JOIN Content_2 ON Content_1.id = Content_2.id
UNION
SELECT Col1, Col2
FROM Content_1
JOIN Content_3 ON Content_1.id = Content_3.id

How to distinctly select tables with different row and column count in mysql?

I am doing a project that involves mysql and I am using tables with different number of column and row. Now I want to select everything from table1 - this contains multiple rows and columns together with table2 that has only 3 columns and 1 row. I tried using
Select * from table1,table2
but the result repeats the row in table2 equal to the row count of table1.
Use "UNION":
Select col1,col2,col3,col4,col5,col6 from table1
UNION
Select col1,col2,col3,null,null,null from table1

What is the difference between these two queries can anybody explain

i thought I achieve same result with the below two queries but I got a different result when I tried, can anybody please explain what is the difference, other than join and subquery.
here t1id is primary column and t2id is referenced column from tbl_1
select * from tbl_1 where t1id in (select t2id from tbl_2);
select t1.* from tbl_1 t1, tbl_2 t2 where t1.t1id = t2.t2id;
EDIT: When I tried I got 93 records for first query and 74 for second query, I changed slightly the first query like :
select * from tbl_1 where t1id in (select distinct t2id from tbl_2);
then I got 40 rows. can anybody explain whats happening.
Thanks in advance
The first query selects all rows from the first table that have an id in the second table.
The second query selects all rows from the first table, and for each of those rows, all rows in the second table. It then filters out rows where the id does not match.
If id is not unique in the second table, the second query can return more rows than the first.
They are both trying to do the same thing: get all rows from tbl_1 whose id value can be found in the t2id column if tbl_2, although the second one will return the same row from tbl_1 multiple times if the id is found multiple times in tbl_2 (not particularly useful).
But both queries are inferior to this one, which also does the sane thing, just mucho re efficiently:
select distinct t1.*
from tbl_1 t1
join tbl_2 t2 on t1.t1id = t2.t2id;
The reason for mismatch between 'in' and 'join' query is:-
tbl1
id name
1 abc
tbl2
id name
1 abc
1 abc
now, select * from tbl1 where id in (select id from tbl2)
although there exists 2 values of id from table 2 i.e. 1, but only one row is fetched from tbl1.
you can try executing the above query as
select * from tbl1 where id in (1,1) --> It will give 1 row only
This is because "In returns true if a specified value matches any value in a subquery or a list"
2nd, the innerjoin query will result in 2 rows as id from tbl1 gets matched with 2 rows from tbl2 table.

left join returning more than expected

Using the following query
select *
from table1
left join table2 on table1.name = table2.name
table1 returns 16 rows and table2 returns 35 rows.
I was expecting the above query to return 16 rows because of the left join, but it is returning 35 rows. right join also returns 35 rows
Why is this happening and how do I get it to return 16 rows?
LEFT JOIN can return multiple copies of the data from table1, if the foreign key for a row in table 1 is referenced by multiple rows in table2.
If you want it to only return 16 rows, one for each table 1 row, and with a random data set for table 2, you can use just a plain GROUP BY:
select *
from table1
left join table2 on table1.name = table2.name
group by table1.name
GROUP BY aggregates rows based on a field, so this will collapse all the table1 duplicates into one row. Generally, you specify aggregate functions to explain how the rows should collapse (for example, for a number row, you could collapse it using SUM() so the one row would be the total). If you just want one random row though, don't specify any aggregate functions. MySQL will by default just choose one row (note that this is specific to MySQL, most databases will require you to specify aggregates when you group). The way it chooses it is not technically "random", but it is not necessarily predictable to you. I guess by "random" you really just mean "any row will do".
Let's assume you have the following tables:
tbl1:
|Name |
-------
|Name1|
|Name2|
tbl2:
|Name |Value |
--------------
|Name1|Value1|
|Name1|Value2|
|Name3|Value1|
For your LEFT JOIN you'll get:
|tbl1.Name|tbl2.Name|Value |
----------------------------
|Name1 | Name1 |Value1|
|Name1 | Name1 |Value2|
|Name2 | NULL | NULL |
So, LEFT JOIN means that all records from LEFT (first) table will be returned regardless of their presence in right table.
For your question you need to specify some specific fields instead of using "*" and add GROUP BY tbl1.Name - so your query will look like
select tbl1.Name, SOME_AGGREGATE_FUNCTION(tbl2.specific_field), ...
from table1
left join table2 on table1.name = table2.name
GROUP BY tbl1.Name
One way to use this is by using the power of SQL distinct.
select distinct tbl1.id, *
from table1 tbl1
left join table2 tbl2 on tbl2.name = tbl1.name
where
....................
Please not that I am also using aliasing.
If the name column is not unique in the tables then you may simply have duplicates on table2.
Try running:
select * from table2 where name not in (select name from table1);
If you get no results back then duplicates on the name column is the reason for the extra rows coming back.
Duplication may be reason. See example in the post
https://alexpetralia.com/posts/2017/7/19/more-dangerous-subtleties-of-joins-in-sql
if you want to join the single latest/earliest relative row from right table, you can limit the join data using min/max primary key and then limiting to 1 row using group Like this:
SELECT * FROM table1
LEFT JOIN (SELECT max(tbl2_primary_col), {table2.etc} FROM table2 GROUP BY name) AS tbl2
ON table1.name = tbl2.name
WHERE {condition_for_table1}
And remember don't use * for left join because it will disable min/max and always return first row.
As per your comment "A random row from table2, as long as name from table1 matches name from table2", you can use the following:
select table1.name, (select top 1 somecolumn from table2 where table2.name = table1.name)
from table1
Note that top 1 is not mysql but it is for SQL Server