Left outer join to two tables - mysql

I have a table 1 with a one to many relationship to table 2.
Table 1 also has a one to many relationship with table 3
I want to combine the results of the join but all im getting is repeated values
Here is the structure:
table 1
reportnumber
1
2
3
table 2
reportnumber col1
1 a
1 b
2 c
3 a
table 3
reportnumber col2
1 x
1 y
1 z
2 w
expected result set
reportnumber col1 col2
1 a x
1 b y
1 z
2 c w
3 a
I'm sure this is possible with a left outer join but i just cant get the syntax right
Any clues?
This is what im trying
select * from table1 a
left outer join table2 b on a.reportnumber=b.reportnumber
left outer join table3 on a.reportnumer=c.reportnumber
But the results look like this
reportnumber col1 col2
1 a x
1 a y
1 a z
1 b x
1 b y
1 b z
...

This isn't easy in MySQL, but you can do it with variables. This has little to do with a join. Or, it has a lot to do with join, but you don't have the right join keys and you don't have full outer join.
The solution is to enumerate the rows from each table with the data columns. Then aggregate using the enumeration and reportnumber:
select reportnumber, max(col1) as col1, max(col2) as col2
from ((select t2.reportnumber, col1, null as col2, #rn2 := #rn2 + 1 as rn
from table2 t2 cross join
(select #rn2 := 0) const
) union all
(select t3.reportnumber, null, t3.col2, #rn3 := #rn3 + 1 as rn
from table3 t3 cross join
(select #rn3 := 0) const
)
) t
group by reportnumber, rn;

Related

SQL query to join two tables with no repeated values?

Table 1
ID | NAME | WARD_ID|
1 A 1
2 B 1
3 C 2
4 D 2
Table 2
ID | MONTH1 | MONTH2 | WARD_ID|
1 9 10 1
2 6 11 1
3 5 12 2
4 13 14 2
I want to join this two table and produce the following output:
ID | NAME | MONTH1 | MONTH2 | WARD_ID|
1 A 9 10 1
2 B 6 11 1
3 C 5 12 2
4 D 13 14 2
In the ON condition of the query I have to keep WARD_ID equal for both the tables. I could not able to figure out the solution. Anyone have any experience with a query like this?
I think you want something like this:
select t1.*, t2.*
from (select t1.*,
(#rn1 := if(#w1 = ward_id, #rn1 + 1,
if#w1 := ward_id, 1, 1)
)
) as rn
from (select t1.* from table1 t1 order by ward_id, id ) t1 cross join
(select #w1 := -1, #rn1 := -1) params
) t1 join
(select t2.*,
(#rn2 := if(#w2 = ward_id, #rn2 + 1,
if#w2 := ward_id, 1, 1)
)
) as rn
from (select t2.* from table2 t2 order by ward_id, id ) t2 cross join
(select #w2 := -1, #rn1 := -1) params
) t1
on t2.ward_id = t1.ward_id and t2.rn = t1.rn;
The subqueries enumerate the rows in each table. The join then uses the enumeration.
This is much simpler in MySQL 8.0, using row_number().
I'm assuming here that ID is intended to be the same from both tables. If so, I think you can do a multi-condition join:
select * from table1 t1
inner join table2 t2
on t1.ID=t2.ID and t1.WARD_ID=t2.WARD_ID
You can do something like:
SET #rn:=0;
SET #rn2:=0;
SELECT *
FROM (
SELECT #rn:=#rn+1 AS rn1, t1.ID, t1.NAME, t1.WARD_ID
FROM t1
GROUP BY t1.WARD_ID, t1.NAME
ORDER BY t1.WARD_ID, t1.NAME
) s1
INNER JOIN (
SELECT #rn2:=#rn2+1 AS rn2, t2.ID, t2.MONTH1, t2.MONTH2, t2.WARD_ID
FROM t2
GROUP BY t2.WARD_ID, t2.MONTH1,t2.MONTH2
ORDER BY t2.WARD_ID, t2.MONTH1,t2.MONTH2
) s2 ON s1.WARD_ID = s2.WARD_ID
AND s1.rn1 = s2.rn2
But it really doesn't reliably sort the tables to join the same rows every time. I still think there isn't a reliable/repeatable way to join the two tables the same every time.
============================================================
http://sqlfiddle.com/#!9/aa2db0/1 <<<< If ID can be used to reliably sort the two tables, you can use it in the ORDER BYs. I've added it in this Fiddle, and included rows in the setup that would fall before the existing records and potentially change the sorting. This also includes more records in Table 2 than there are in Table 1, so would possibly result in duplicated rows. These new rows are ignored since they can't be matched between tables.

How to select random rows where the sum of a column equals to X - MySQL

How i can select random rows of a table when the sum of a column equals to a value ? (MySQL)
Value : 3
Name Price
------------------------
A 1
B 2
C 1
D 3
E 2
I wan to get all possibilities (A + B, D, E + C...).
I have tried to do this :
SELECT * FROM table HAVING SUM(column) = 3 ORDER BY RAND();
Thank's
Thibeault
You need to join the table with itself to get pairs of rows.
SELECT t1.name as name1, t1.price as price1, t2.name AS name2, t2.price AS price2
FROM yourTable AS t1
JOIN yourTable AS t2 ON t1.price + t2.price = 3
ORDER BY RAND()
LIMIT 1

MySQL select unique records on two columns

How do I select rows where two columns are unique?
Given table
id col1 col2
1 a 222
2 b 223
3 c 224
4 d 224
5 b 225
6 e 226
How do remove the duplicates in col1 and the duplicates in col2, to get rows unique to whole table,
So that result is
id col1 col2
1 a 222
6 e 226
Is there a better way than using sub queries?
SELECT * FROM table WHERE id
IN (SELECT id FROM table WHERE col1
IN (SELECT col1 FROM table GROUP BY col1 HAVING(COUNT(col1)=1))
GROUP BY col2 HAVING(COUNT(col2)=1))
This should work using exists:
select *
from yourtable y
where not exists (
select 1
from yourtable y2
where y.id != y2.id
and (y.col1 = y2.col1
or y.col2 = y2.col2))
SQL Fiddle Demo
Here's an alternative solution using an outer join as I've read mysql sometimes doesn't do well with exists:
select *
from yourtable y
left join yourtable y2 on y.id != y2.id
and (y.col1 = y2.col1
or y.col2 = y2.col2)
where y2.id is null;
More Fiddle
You can also do this by aggregating along each dimension:
select t.*
from table t join
(select col1
from table t
group by col1
having count(*) = 1
) t1
on t.col1 = t1.col1 join
(select col2
from table t
group by col2
having count(*) = 1
) t2
on t.col2 = t2.col2;
This method seems like a very direct translation of the user requirements.

Splitting a result into three columns

Say I have a table 'alphabet'. This is just a basic representation/example.
id word
1 a
2 b
3 c
4 d
5 e
6 f
7 g
8 h
9 i
10 j
11 k
12 l
13 m
Now assume I am restricted to just a single query (with subqueries) due to a language restriction or otherwise.
I want my 'result' to be as follows:
row col1 col2 col3
1 a b c
2 d e f
3 g h i
4 j k l
5 m
Now I've gotten somewhat close to this by emulating a Full Outer Join in MySQL by following the instructions found here: Full Outer Join in MySQL combined with a sub-query on the same table using something along the lines of:
SELECT id,word FROM table WHERE MOD(id,3)=1
This isn't particularly perfect, as it requires me to assume that the ids follow each-other perfectly sequentially, but I haven't been able to think of a better method at the time. Since last I recall, LIMIT and OFFSET do not take sub-queries.
However, following this thought through, results into something along the lines of:
row col1 col2 col3
1 a
2 d
3 g
4 j
5 m
6 b
7 e
8 h
9 k
10 c
11 f
12 i
13 l
13 m
Is there a way to get my desired format?
And note that normally, the desired way to do this is indeed to just do three calls with a limit-offset call based on a count(). But /is this possible/ to be done in a single call?
I doesn't found any use case for this, but it is what you want:
SELECT
FLOOR((id - 1)/3) + 1 id,
MAX(CASE WHEN MOD(id - 1,3) = 0 THEN word END) col1,
MAX(CASE WHEN MOD(id - 1,3) = 1 THEN word END) col2,
MAX(CASE WHEN MOD(id - 1,3) = 2 THEN word END) col3
FROM tbl
GROUP BY FLOOR((id - 1)/3)
SQLFIDDLE DEMO
Notice, that this will work only in case when you have sequential Id starting from 1.
Is this what you need?
SELECT FLOOR((col1.id - 1) / 3 + 1) AS id, col1.word AS col1, col2.word AS col2, col3.word AS col3
FROM alphabet col1
LEFT JOIN alphabet col2 ON col1.id = col2.id - 1
LEFT JOIN alphabet col3 ON col2.id = col3.id - 1
WHERE col1.id % 3 = 1;
How about something like
Select t1.id as `row`, t1.word as col1, t2.word as col2, t3.word as col3
From alphabet t1
left join alphabet t2 on t2.id = t1.id + 5
left join alphabet t3 on t3.id = t1.id + 10
Where t1.id <= 5
Taking Halmet Hakobyan's answer, finishing this off:
SELECT
FLOOR((rank - 1)/3) + 1 rank,
MAX(CASE WHEN MOD(rank - 1,3) = 0 THEN word END) col1,
MAX(CASE WHEN MOD(rank - 1,3) = 1 THEN word END) col2,
MAX(CASE WHEN MOD(rank - 1,3) = 2 THEN word END) col3
FROM (SELECT #rn:=#rn+1 AS rank, `id`,`word` from tbl) as tbl, (SELECT #rn:=0) t2
GROUP BY FLOOR((rank - 1)/3)
SQLFIDDLE DEMO
This will work even if the ids are not in sequence.

Merging 2 result sets of colums of an mysql query into one

Example:
First Query:
select A,B,C from tb1;
---------------
A B C
---------------
1 1 3
2 1 4
Second Query:
select E from tb2;
---------------
E
---------------
8
9
The required result format should be like this:-
-----------------------
A B C E
-----------------------
1 1 3 8
2 1 4 9
Please tell me the query how to get the result set.
to make your tables better structured if you can add in both tables a column id to identify the row number of each table.
then you can easily merge two table which have same id . the relation here is the id column.
then you could do this
select A, B, C , E from Table1 t1
inner join Table2 t2
on t1.id = t2.id
please see structured tables in this DEMO HERE
THE RESULT:
A B C E
1 1 3 8
2 1 4 9
hope it helps you !
SQL tables are inherently unordered. This poses a problem, because there is nothing in your table to specify the ordering of the rows, which seems to be the connection between the two tables.
So, you have to hold your breath and make some assumptions. The particular assumption is that the data returned by a select is the actual order you want in the table (it could be different if you have deletes in the table or are running in a parallel environment).
The following code adds an id to each table. This id can then be used for the join:
select t1.A, t1.B, t1.C, t2.D
from (select t1.*, #rn := #rn + 1 as id
from tbl1 t1 cross join (select #rn := 0)
) t1 left outer join
(select t2.*, #rn := #rn + 1 as id
from tbl2 t2 cross join (select #rn := 0)
) t2
on t1.id = t2.id
Hi may be it's help for you
you can try like this
SELECT * FROM tb1,tb2
And you get output like
-----------------------
A B C E
-----------------------
1 1 3 8
2 1 4 9