SQL Join 2 tables with IDs in one row - mysql

I'm trying to join data from two tables into 1 row but i can't seem to figure out how to achieve this.
Table 1 structure
id, name, number, email
Table 2 structure
id, friends
The thing is in table 1, id is unique, whereas in table 2 id is not, he can have many friends. (Ofc this is all example).
I'm trying to get a row looking like this
id, name, number, email, friend[1], friend[2] etc.
Any ideas how i can achieve this, or if i need to change my db structure to be able to get this result?
*Note (he only has a choice of 8 different friends).

The most efficient way would be to group your results together with a JOIN statement;
SELECT T1.*, F1.Friend
FROM Table_1 as T1
LEFT JOIN Table_2 as F1
ON T1.id = F1.id
Then iterate through each of the rows in your mysql client.
Another way to do this is with multiple joins to the same table, but without a better way to distinguish the individual friend records you end up doing some messy exclusions in your JOIN statements.
SELECT T1.*, F1.Friend, F2.Friend, F3.Friend, [snip/] F8.Friend
FROM Table_1 as T1
LEFT JOIN Table_2 as F1
ON T1.id = F1.id AND F1.Friend NOT IN (F2.Friend, F3.Friend, [snip/] F8.Friend)
LEFT JOIN Table_2 as F2
ON T1.id = F2.id AND F2.Friend NOT IN (F1.Friend, F3.Friend, [snip/] F8.Friend)
LEFT JOIN Table_2 as F3
ON T1.id = F3.id AND F3.Friend NOT IN (F1.Friend, F2.Friend, F4.Friend, [snip/] F8.Friend)
[big snip/]
LEFT JOIN Table_2 as F8
ON T1.id = F8.id AND F8.Friend NOT IN (F1.Friend, F2.Friend, [snip/] F7.Friend)

Have you considered implementing group_concat? (http://www.mysqlperformanceblog.com/2006/09/04/group_concat-useful-group-by-extension/)
Regardless of the fact that there would only be 8 friends per user, it isn't practical/efficient solution to generate columns based on joined rows.

Related

SQL Inner Joins Giving Incorrect Count Values in MS ACCESS

I am trying to use join to connect multiple tables in MS Access to get count values. But I don;t know it gives wrong count values. If I try to join them individually, then it gives me correct count values.
I have 3 Tables. Table 2 and Table 3 are independent and are connected to Table 1. Test 2 and test 3 are basically text values and I want to count the rows .
Table1(ID1(Primary Key),Name)
Table2(ID2(Primary Key), ID1(Foreign Key), Test2)
Table3 (ID3(Orimary Key), ID1(Foreign Key), Test3)
The Query that I get from MS Access is given below:
SELECT Table1. ID1, Count(Table2.Test2) AS CountOfTest2, Count(Table3.Test3) AS CountOfTest3
FROM (Table1 INNER JOIN Table2 ON Table1.ID1 = Table2.ID2)
INNER JOIN Table3 ON Table1. ID1 = Table3.ID3
GROUP BY Table1.ID1;
But this gives me wrong Count Values.
Can someone please help me.
Thanks.
When I use it individually, it gives me correct count value:
SELECT Table1. ID1, Count(Table2.Test2) AS CountOfTest2
FROM Table1 INNER JOIN Table2 ON Table1.ID1 = Table2.ID1
GROUP BY Table1.ID1;
SELECT Table1. ID1, Count(Table3.Test3) AS CountOfTest3
FROM Table1 INNER JOIN Table3 ON Table1.ID1 = Table3.ID1
GROUP BY Table1.ID1;
But when I try to join Table1, Table2 and Table 3 in MS Acces, it gives me incorrect count values.
SELECT Table1. ID1, Count(Table2.Test2) AS CountOfTest2, Count(Table3.Test3) AS CountOfTest3 FROM (Table1 INNER JOIN Table2 ON Table1.ID1 = Table2.ID1) INNER JOIN Table3 ON Table1. ID1 = Table3.ID1 GROUP BY Table1.ID1
As per my understanding it is taking the count value of 1st query in the parenthesis and multiplying it with the count values of the other inner join.
I have tried many things but don't know what to do. Access adds parenthesis for some reason.
If I can assume test2 and test 3 are unique to each record (perhaps it would be better to count the PK?)
SELECT Table1.ID1
, Count(distinct Table2.Test2) AS CountOfTest2
, Count(distinct Table3.Test3) AS CountOfTest3
FROM Table1
INNER JOIN Table2
ON Table1.ID1 = Table2.ID2
INNER JOIN Table3
ON Table1.ID1 = Table3.ID3
GROUP BY Table1.ID1;
Or you may have to get the counts before the joins though the use of inline views. You could use window functions if MSSQL SERVER but Access needs the inline views.
SELECT A.ID1
, B.CountOfTest2
, C.CountOfTest3
FROM Table1 A
INNER JOIN (SELECT Table2.ID2, count(table2.test) as CountOfTest2
FROM Table2
GROUP BY Table2.id) B
ON Table1.ID1 = B.ID2
INNER JOIN (SELECT Table3.id, count(table3.test3) as CountOfTest3
FROM Table3
GROUP BY Table3.id) C
ON B.ID1 = C.ID3
GROUP BY A.ID1;
Yup i had the same problem when i was trying to do this. just use the double sql function to counteract the html and you should be good. once the query has been doubled it will react like a C++ quota statement. If this fails you can always just quantify the source fields to adhear to the table restrictions. its actually a piece of cake i hope this helped.

Generic query for MySQL and PGSQL

I want to create a generic query which work with MySQL and PostgreSQL.
For this query, I need to select all column in 3 tables but the result need to have a distinct clause on the ID to eliminate duplicates rows.
Actually in the database, there is 6 records but just 3 are differents:
One of them appears 3 times, an other appears 2 and the last just on.
Records which appears many time are exactly the same and I just want keep one of each.
This is a picture of the 6 records:
And me I want that:
Here is the MySQL Query:
SELECT
*
FROM
table_1
INNER JOIN table_2
ON table_1.id = table_2.table_1_id
INNER JOIN table_3
ON table_2.table_3_id = table_3.id
WHERE
table_3.type = 'foo'
GROUP BY
table_1.id
And this is the PostgreSQL query:
SELECT DISTINCT ON (table_1.id)
*
FROM
table_1
INNER JOIN table_2
ON table_1.id = table_2.table_1.id
INNER JOIN table_3
ON table_2.table_3_id = table_3.id
WHERE
table_3.type = 'foo'
I don't find how to create just one query which work with MySQL and PostgreSQL
Try to first get the distinct ids of the first table, then join the rest on to them.
Though, you will still get somewhat random values for table_1 I guess, if there are multiples ids with different values to them and you not specifying which you want.
SELECT
table_1.*, table_2.*, table_3.*
FROM
(SELECT table_1.id FROM table_1 GROUP BY table_1.id) AS distinctIds
INNER JOIN table_1 ON table_1.id = distinctIds.id
INNER JOIN table_2 ON distinctIds.id = table_2.table_1_id
INNER JOIN table_3 ON table_2.table_3_id = table_3.id
WHERE
table_3.type = "foo"

Join two tables on two columns, even if table 2 does not have row

What I am trying to do is join two tables, lets call them t1 and t2 on two columns. id and name, for this example. t1 will always have id and name, but t2 won't always have id and name. t1 has more columns like viewes, reports, and t2 has other columns that need to be joined. My question is, how can I show 0's for t2's columns if they don't exist?
I hav something similar to this, that joins tables only if both tables' rows have some value.
SELECT
date(t1.start_time) date,
t1.name,
t1.viewes,
t1.reports,
t2.col5,
t2.col6
from
table1 t1
left outer join table2 t2
on t2.name = t1.name and date(t2.start_time) = date(t1.start_time)
group by
1,2
order by
1 desc,
2 asc
;
I have lot's of experience with MySQL, but sometimes find that things need to be hacked to work correctly. What's your suggestion for this problem?

Can I take the results from two rows and combine them into one?

I have 2 rows of data in a mysql database. Both rows are identical with the exception of one column. What I am looking for is a query that will produce a single row with both distinct values. Can someone please help me out?
An example of the data is:
1 Administrator Test 2009-08-17 03:57:35
1 Miller Test 2009-08-17 03:57:35
What I need is this:
1 Administrator Miller Test 2009-08-17 03:57:35
DISTINCT won't give it to me. I need the additional column added or appended to the result set.
This is the code I am trying to use.
SELECT
t2.msg_id,
t3.lname AS sender,
t4.lname AS recipient
FROM
mail_message AS t1
Inner Join mailbox AS t2 ON t1.msg_seq = t2.msg_seq
Inner Join employee AS t3 ON t3.employee_id = t2.employee_id
INNER JOIN employee AS t4 ON t3.employee_id = t4.employee_id
Sure. You can JOIN the table onto a copy of itself, with a technique something like this:
SELECT t1.*, t2.name
FROM the_table AS t1
INNER JOIN the_table AS t2 ON (t1.id = t2.id AND t1.test = t2.test AND t1.date_column = t2.date_column AND t1.name < t2.name)
Here we arbitrarily name one copy of the table t1 and the other t2 and join rows that are identical except for the name.
Note that I do not simply do a != test on the name, since that would result in two matching rows: one where Administrator is in t1 and the other where Administrator is in t2. To distinguish one identical table from the other, I assert that t1 will always be the one with a "smaller" (i.e., earlier alphabetically) name.
If there can be three or more identical rows, this will still work, but will return several matches. For example, if A, B, and C are all names in otherwise identical rows, you'd get:
A B
B C
A C

How to retrieve non-matching results in mysql

I'm sure this is straight-forward, but how do I write a query in mysql that joins two tables and then returns only those records from the first table that don't match. I want it to be something like:
Select tid from table1 inner join table2 on table2.tid = table1.tid where table1.tid != table2.tid;
but this doesn't seem to make alot of sense!
You can use a left outer join to accomplish this:
select
t1.tid
from
table1 t1
left outer join table2 t2 on
t1.tid = t2.tid
where
t2.tid is null
What this does is it takes your first table (table1), joins it with your second table (table2), and fills in null for the table2 columns in any row in table1 that doesn't match a row in table2. Then, it filters that out by selecting only the table1 rows where no match could be found.
Alternatively, you can also use not exists:
select
t1.tid
from
table1 t1
where
not exists (select 1 from table2 t2 where t2.tid = t1.tid)
This performs a left semi join, and will essentially do the same thing that the left outer join does. Depending on your indexes, one may be faster than the other, but both are viable options. MySQL has some good documentation on optimizing the joins, so you should check that out..