join multiple columns with single column in mysql - mysql

I have 2 tables as follows
t1:
id code field1 field2
1 1000 a1111 a2222
2 2000 b1111 b2222
3 1000 a3333 a4444
4 2000 b3333 b4444
5 2000 b5555 b6666
6 3000 c1111 c2222
7 3000 c3333 c4444
8 3000 c5555 c6666
t2:
t2id t1_code var1
1 1000 xxxx
2 2000 yyyyy
3 3000 zzz
4 3000 mmm
i want the result table as:
code field1 field2 t1_code var1
1000 a3333 a4444 1000 xxxx
1000 a1111 a2222 null null
2000 b3333 b4444 2000 yyyyy
2000 b5555 b6666 null null
2000 b1111 b2222 null null
3000 c1111 c2222 3000 mmm
3000 c3333 c4444 3000 zzz
3000 c3333 c4444 null null
i tried :
SELECT t1.code, t1.field1, t1.field2, t2.t1_code, t2.var1
FROM t2, t1
WHERE t1_code = code
ORDER BY code
is not giving me the answer.
Please help...

Okay, you want the join to go to the "first" matching row in t1 (where "first" means lowest id).
Here is almost a way to do it:
SELECT t1.code, t1.field1, t1.field2, t2.t1_code, t2.var1
FROM t1 left outer join
(select t1.code, min(id) as minid
from t1
group by t1.code
) t1min
on t1.id = t1min.minid left outer join
t2
on t2.t1_code = t1min.code;
What this does is join the original table to another table to find the minimum id for each code. By joining on the ids, the t1min.code will only have values at the min ids. The final join just brings in the code for these.
EDIT:
The actual problem is a bit more complicated. I think the best way is simply to enumerate the values in each table and do the join with two keys:
select t1.code, t1.field1, t1.field2, t2.t1_code, t2.var1
from (select t1.*,
#rn1 := if(#code = code, #rn1 + 1, 1) as rn, #code := code
from t1 cross join
(select #rn1 := 0, #code := '') const
order by code, id
) t1 left outer join
(select t2.*,
#rn2 := if(#code = t1_code, #rn2 + 1, 1) as rn, #code := t1_code
from t2 cross join
(select #rn2 := 0, #code := '') const
order by t1_code, t2id
) t2
on t1.code = t2.t1_code and t1.rn = t2.rn
order by t1.id;

Related

How to JOIN the same table with itself using ORDER BY RAND()?

I want to get random combinations of id of a table with itself.
SELECT id FROM t1
SELECT id as id2 FROM t1 ORDER BY RAND()
SELECT id as id3 FROM t1 ORDER BY RAND()
How can I JOIN these queries to get
SELECT id,id2,id3
1 random_id random_id
2 random_id random_id
3 random_id random_id
4 random_id random_id
5 random_id random_id
In other words, what can be the point of JOINing to simply place these three SELECTs side by side.
It is beneficial to create a unique combination, but with the above query ORDER BY RAND() can repeat the same id to id2 and id3. The former case is ideal, but the latter sufficiently works for me.
If you are using MySQL 8+, then ROW_NUMBER might work here:
WITH cte AS (
SELECT id,
ROW_NUMBER() OVER (ORDER BY id) rn1,
ROW_NUMBER() OVER (ORDER BY RAND(UNIX_TIMESTAMP())) rn2,
ROW_NUMBER() OVER (ORDER BY RAND(UNIX_TIMESTAMP()+1)) rn3
FROM t1
)
SELECT
t1.id,
t2.id AS id2,
t3.id AS id3
FROM cte t1
INNER JOIN cte t2
ON t1.rn1 = t2.rn2
INNER JOIN cte t3
ON t1.rn1 = t3.rn3;
The demo below was from a sample table containing the id values from 1 to 10 inclusive.
Demo
If you truly want random, then repeats are allowed. That suggests:
select t.*,
(select t2.id
from t t2
order by rand()
limit 1
) as id2,
(select t3.id
from t t3
order by rand()
limit 1
) as id3
from t;
If you want permutations in older versions of MySQL, then variables are handy:
select t.id, t1.id, t2.id
from (select t.id, (#rn := #rn + 1) as seqnum
from t cross join
(select #rn := 0) params
) t join
(select t.id, (#rn1 := #rn1 + 1) as seqnum
from (select t.* from t order by rand()) t cross join
(select #rn1 := 0) params
) t1
using (seqnum) join
(select t.id, (#rn2 := #rn2 + 1) as seqnum
from (select t.* from t order by rand()) t cross join
(select #rn2 := 0) params
) t2
using (seqnum);
In MySQL 8+, Tim's answer is the best approach.
Here is a db<>fiddle
For this sample data of sequential ids from 1 to n, this query that uses string functions will work and will return in the columns id2 and id3 all if the ids once:
select t1.id,
find_in_set(t1.id, t2.ids2) id2,
find_in_set(t1.id, t3.ids3) id3
from tablename t1
cross join (
select group_concat(id order by rand()) ids2
from tablename
) t2
cross join (
select group_concat(id order by rand()) ids3
from tablename
) t3
See the demo.
Results (like):
| id | id2 | id3 |
| --- | --- | --- |
| 1 | 5 | 4 |
| 2 | 2 | 5 |
| 3 | 1 | 2 |
| 4 | 4 | 3 |
| 5 | 3 | 1 |

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.

insert to from multiple to one table in mysql

I want to select from two table column datas and insert it into another table I can this but it copy 6 times.
I tried this code it works but insert 6 time in to table3.
insert into table3(LisanNo , UserName, table1ID,
NameAndLastName , table2Id)
select table1.LisansNo, table1.UserName, table1.Id,
table2.NameAndLastName,table2.Id
form table1, tabl2;
Enter code here-
**Table1**
id LisansNo UserName
1. f3ewrwer aaa
2. r3we3 bbb
**Table2**
id NameLastName
3. john ddd
4. hhhhh
9. yyyy
11. terere
I want to insert this Two table to another table.
table 3
id LisanNo UserName table1ID NameLastName Table2ID
1. f3ewrwer aaa 1 john ddd 3
2. r3we3 bbb 2 hhhhh 4
3. yyyy 9
4. terere 11
You seem to want to list the values vertically. This is not a very SQL'ish thing to do, but you can accomplish it:
select t1.LisansNo, t1.UserName, t1.Id,
t2.NameAndLastName, t2.Id
from (select t1.*, (#rn1 := #rn1 + 1) as seqnum
from table1 cross join
(select #rn1 := 0) params
) t1 left join
(select t2.*, (#rn2 := #rn2 + 1) as seqnum
from tabl2 t2 cross join
(select #rn2 := 0) params
) t2
on t1.seqnum = t2.seqnum;

SQL join with three tables, one table returns unknown number of results, dont want duplicate rows

OK, so I'm using node and MySQL, having issues with a query.
I have three tables, we'll call them T1, T2, and T3. T1 has a primary key, we'll call it T1.id. T3 also has a primary key, T3.id.
T2 has a primary key, T2.id, and foreign keys which point to T1.id (FK1) and T3.id (FK3). So now let's look at a sample data set:
T1_____ T2________ T3_____
id -name | id -FK1 -FK3 | id -name
1 johnny | 1 .... 1 .... 1 .. | 1 .. MN
2 william | 2 .... 1 .... 2 .. | 2 .. FL
3 joseph | 3 .... 1 .... 3 .. | 3 .. CA
4 bobbie | 4 .... 2 .... 2
------------| 5 .... 2 .... 3
------------| 6 .... 3 .... 1
------------| 7 .... 3 .... 2
------------| 8 .... 3 .... 3
I want a query that will return columns from T1, and then join (unknown number of) columns of T2 for each match, and then for each T2 match, join columns from T3 for its corresponding match.
So, for example, the first row would be:
T1.name T2.1.id T2.1.T3.name T2.2.id T2.2.T3.name T2.3.id T2.3.T3.name
johnny 1 MN 2 FL 3 CA
*** Sorry for the formatting. Is this doable, or do I need to use a non-relational DB like Mongo or Couchbase?
Simplified solution: Merge all the data from T3 table into one column in the result set.
SELECT t1.name,
GROUP_CONCAT(t3.id,' ',t3.name SEPARATOR ', ') as data
FROM t1
JOIN t2
ON t2.fk1 = t1.id
JOIN t3
ON t3.id = t2.fk2
GROUP BY t1.id;
It would produce result
T1.name | data
johnny | 1 MN, 2 FL, 3 CA
with configurable delimiters.
Extended solution: Prepare dynamic query taking advantage of pivoting:
SELECT GROUP_CONCAT('MAX(CASE WHEN ind=', #i := #i+1, ' THEN x.t3id ELSE NULL END) AS col', #i, 'id,MAX(CASE WHEN ind=', #i, ' THEN x.name ELSE NULL END) AS col', #i, 'name')
FROM t2,
(SELECT #i := 0) init
WHERE t2.fk1 = (
SELECT fk1
FROM (
SELECT t2.fk1,
COUNT(t2.fk2) as cnt
FROM t2
GROUP BY t2.fk1
ORDER BY cnt DESC
LIMIT 1
) tmp
)
INTO #sql;
SET #sql = CONCAT('SELECT x.t1name,', #sql, ' FROM ( SELECT #i := IF(#id = tmp.id, #i+1, 1) as ind, #id := tmp.id as id, tmp.t1name, tmp.t3id, tmp.name FROM (SELECT t1.id, t1.name as t1name, t3.id as t3id, t3.name FROM t1 JOIN t2 ON t2.fk1 = t1.id JOIN t3 ON t3.id = t2.fk2,(SELECT #i := 1, #id := 0) init ORDER BY t1.id) tmp) x GROUP BY x.id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
This approach will create and execute query looking like:
SELECT x.t1name,
MAX(CASE WHEN ind = 1 THEN x.t3id ELSE NULL END) AS col1id,
MAX(CASE WHEN ind = 1 THEN x.name ELSE NULL END) AS col1name,
MAX(CASE WHEN ind = 2 THEN x.t3id ELSE NULL END) AS col2id,
MAX(CASE WHEN ind = 2 THEN x.name ELSE NULL END) AS col2name,
MAX(CASE WHEN ind = 3 THEN x.t3id ELSE NULL END) AS col3id,
MAX(CASE WHEN ind = 3 THEN x.name ELSE NULL END) AS col3name
FROM (
SELECT #i := IF(#id = tmp.id, #i+1, 1) as ind,
#id := tmp.id as id,
tmp.t1name,
tmp.t3id,
tmp.name
FROM (
SELECT t1.id,
t1.name as t1name,
t3.id as t3id,
t3.name
FROM t1
JOIN t2
ON t2.fk1 = t1.id
JOIN t3
ON t3.id = t2.fk2,
(SELECT #i := 1, #id := 0) init
ORDER BY t1.id
) tmp
) x
GROUP BY x.id;
Which gives the following result:
t1name | col1id | col1name | col2id | col2name | col3id | col3name
johnny | 1 | MN | 2 | FL | 3 | CA
william | 2 | FL | 3 | CA | NULL | NULL
There is one limitation here however, regarding the group_concat function
The result is truncated to the maximum length that is given by the group_concat_max_len system variable, which has a default value of 1024.
Try the following way using LEFT JOIN and group_concat
select
T1.name,
group_concat(T2.id) as T2Ids,
group_concat(T3.name) as States
from T1 left join T2 ON T1.id = T2.FK1
left join T3 ON T3.id = T2.FK3
group by T1.id

Select rows from a table based on max value in different table

I'm looking for a MySQL query to extract values like in the following example:
TABLE1:
ID name
25 ab
24 abc
23 abcd
22 abcde
21 abcdef
TABLE2:
ID ID_TABLE1 total
1 25 0
2 25 1
3 25 2
4 25 3
5 23 1
6 22 0
7 22 1
8 21 0
9 21 2
10 24 10
11 24 7
I want to return all TABLE1 rows where max value of total column (in TABLE2) is < 3.
So the results should be:
ID name
23 abcd
22 abcde
21 abcdef
I tried this:
SELECT t1.*
FROM TABLE1 t1
INNER JOIN (
SELECT MAX( total ) AS max_total, ID_TABLE1
FROM TABLE2
GROUP BY total, ID_TABLE1
) t2
ON t1.ID = t2.ID_TABLE1
WHERE t2.max_total < 3
but it's not the result I want.
Try this:
SELECT t1.ID, t1.name
FROM TABLE1 t1
INNER JOIN (SELECT ID_TABLE1, MAX(total) AS max_total
FROM TABLE2
GROUP BY ID_TABLE1
) t2 ON t1.ID = t2.ID_TABLE1
WHERE t2.max_total < 3;
Your inner query groups the results by id_table and by total. Since the maximum of total per total is the value itself, it makes the inner query somewhat meaningless. Just remove the total from the group by clause and you should be OK:
SELECT t1.*
FROM TABLE1 t1
INNER JOIN (
SELECT MAX( total ) AS max_total, ID_TABLE1
FROM TABLE2
GROUP BY ID_TABLE1
) t2
ON t1.ID = t2.ID_TABLE1
WHERE t2.max_total < 3
SELECT t1.*
FROM TABLE1 t1
INNER JOIN (
SELECT MAX( total ) AS max_total, ID_TABLE1
FROM TABLE2
GROUP BY ID_TABLE1
having t2.max_total < 3
) t2
ON t1.ID = t2.ID_TABLE1
Here is a way to do using left join without using any subquery and group by clauses.
select t1.* from table1 t1
join table2 t2
on t1.id = t2.id_table1
left join table2 t3 on
t2.id_table1 = t3.id_table1
and t2.total < t3.total
where t3.id is null
and t2.total < 3
Another way is
select t1.* from table1 t1
join table2 t2 on t1.id = t2.id_table1
where not exists(
select 1 from table2 t3
where t2.id_table1 = t3.id_table1
and t2.total < t3.total
)
and t2.total < 3;
SELECT t1.*
FROM TABLE1 t1
INNER JOIN (
SELECT MAX( total ) AS max_total, ID_TABLE1
FROM TABLE2
where total > 3 GROUP BY total, ID_TABLE1
) t2
ON t1.ID != t2.ID_TABLE1
There's a simpler way without using GROUP or MAX:
SELECT * FROM table1
WHERE id NOT IN (
SELECT id_table1 FROM table2 WHERE total >= 3
);
The subquery selects all rows in table2 that have a total >= 3. Then we select those rows from table1 that are not in the subquery result.