I have two arrays like this,
First Table (infos):
------------------------------
| ID | User1 | User2 | User3 |
------------------------------
| 1 | 20 | 30 | 12 |
------------------------------
Second Table (Users):
---------------------
| ID | Name | Email |
---------------------
| 12 | Test | Test# |
---------------------
| 20 | Bla | Test# |
---------------------
| 30 | Bate | Test# |
---------------------
I want to get the information of users on one row from the IDs on the first table.
I try by getting The row from the first table and fetching on users, but I want to optimize the function with just one Query.
SELECT * FROM infos;
SELECT * FROM Infos i,Users u WHERE u.ID = u.User1 (or 2 ...)
Is there any solution ?
You could use joining the table users 3 times, one for each userid you want show the related name (or other values):
select a.id
, a.user1
, b.Name as user1name
, a.user2
, c.name as user2name
, a.user3
, d.name as user3name
from infos a
inner join Users b on a.user1 = b.id
inner join Users c on a.user1 = c.id
inner join Users d on a.user1 = d.id
And just as suggested, you should not use old implicit join syntax based on comma-separated table names and where clause, you should use (since 1992) explicit joins. This syntax performs the same query, but is more clear.
This is a design error. Use a N:N relation (an additional table) to allow any number of users for the first table. With the relation, other queries will be easier.
A relation table looks like this:
create table relation
(
table1_id int unsigned not NULL,
table2_id int unsigned not NULL,
primary key(table1_id,table2_id)
);
A typical query (and I dislike a.* generally):
select a.*, b.*
from table1 a, table2 b, relation r
where r.table1_id = a.id
&& r.table2_id = b.id
Related
Let me start by saying this should be a relatively simple problem which is / was made unnecessary complicated by bad Database design (not by me) that said im also no expert in mysql.
Consider the following
Table Schedule
Note how the columns homeID and visitorID contains the names of the teams and not the actual teamID's
In a bid to fix this I created a new table with columns containing teamID AND teamName as can be seen by below image.
Table Teams
My Problem(s)
I must get the teamID from table Teams for BOTH home team AND away team
So I created the Teams table and this simple script:
SELECT schedule.*, teams.*
FROM schedule
JOIN teams ON schedule.homeID = teams.teamName OR schedule.visitorID = teams.teamName
WHERE schedule.gameID = 411
LIMIT 1 #added Limit1 else the code generates to rows
Output of mysql Script
Limit 1
Notice above how teamID is only generated for 1 team with Limit 1
No Limit Statement (Double Iteration)
Notice above how teamID can get retrieved for BOTH teams. Problem is its doing a double iteration.
TLDR; The above presents the following problems
Firstly the script will generate two outputs one for home team and once for away team. As to be expected however I cant have that.
As a workaround to Problem number 1 -- I added Limit 1 the problem I get with Limit though is that it only gives back a single teamID (as to be expected, I guess)
Question
How can I get BOTH teamID's from table teams with a single iteration? Hope this make sense....
Extra
A demo of application with hard coded team names looks like this (just to give an idea of what they are trying to achieve)
Sounds like you want to join teams twice to schedule.
SELECT s.*,
th.*,
ta.*
FROM schedule s
INNER JOIN teams th
ON s.homeid = th.teamname
INNER JOIN teams ta
ON s.visitorid = ta.teamname
WHERE s.gameid = 411;
I guess that you want to show both team in one row instead of two rows.
If yes, then you need to join the table teams twice.
Consider this demo: http://www.sqlfiddle.com/#!9/bb5e61/1
This join will collect both teams into one row:
SELECT s.*,
t1.teamId as homeId_teamId,
t1.teamCode as homeId_teamCode,
t1.teamName as homeId_teamName,
t2.teamId as visitorId_teamId,
t2.teamCode as visitorId_teamCode,
t2.teamName as visitorId_teamName
FROM Schedule s
JOIN Teams t1 ON s.homeId = t1.teamName
JOIN Teams t2 ON s.visitorId = t2.teamName;
| id | homeId | visitorId | homeId_teamId | homeId_teamCode | homeId_teamName | visitorId_teamId | visitorId_teamCode | visitorId_teamName |
|----|--------|-----------|---------------|-----------------|-----------------|------------------|--------------------|--------------------|
| 1 | Poland | Colombia | 1 | PL | Poland | 2 | CO | Colombia |
However you can also consider LEFT joins instead on INNER joins, which will work in a case where there is no relevant data in the TEAMS table:
SELECT s.*,
t1.teamId as homeId_teamId,
t1.teamCode as homeId_teamCode,
t1.teamName as homeId_teamName,
t2.teamId as visitorId_teamId,
t2.teamCode as visitorId_teamCode,
t2.teamName as visitorId_teamName
FROM Schedule s
LEFT JOIN Teams t1 ON s.homeId = t1.teamName
LEFT JOIN Teams t2 ON s.visitorId = t2.teamName;
| id | homeId | visitorId | homeId_teamId | homeId_teamCode | homeId_teamName | visitorId_teamId | visitorId_teamCode | visitorId_teamName |
|----|----------|-----------|---------------|-----------------|-----------------|------------------|--------------------|--------------------|
| 1 | Poland | Colombia | 1 | PL | Poland | 2 | CO | Colombia |
| 3 | Ya Majka | Poland | (null) | (null) | (null) | 1 | PL | Poland |
| 2 | Ya Majka | Rossija | (null) | (null) | (null) | (null) | (null) | (null) |
Here are the scripts that make up the tables from the examples
CREATE TABLE Schedule(
id int, homeId varchar(20),visitorId varchar(20)
);
INSERT INTO Schedule VALUES
(1, 'Poland', 'Colombia' ),(2,'Ya Majka','Rossija'),
(3,'Ya Majka','Poland');
CREATE TABLE Teams(
teamId int, teamCode varchar(10), teamName varchar(20)
);
INSERT INTO Teams VALUES
(1, 'PL', 'Poland' ),(2,'CO','Colombia'),(3,'US','United States');
You can use a subquery (two of them in the same query) to solve this:
select
gameID,
weekNum,
gameTimeEastern,
(select teamName from teams where teamID = schedule.homeID) as homeName,
homeScore,
(select teamName from teams where teamID = schedule.visitorID) as visitorName,
visitorScore from schedule;
This doesn't get all the columns from schedule, just an example to show how it works. If you need various queries (including select *, though this isn't a good practice except for testing), you could create a view based on a query like the above (with ALL columns from schedule, except homeID and visitorID that get replaced with sub-queries from the teams table). Then you can place queries against that view - and they will work like the original table where you had team names directly in it.
I have two tables with similar information. First Table is suppliers and other table is suppliers_contacts. Is there a way to merge the two columns into one?
My suppliers table looks like this:
id | contacts_name | email
-- | ------ | -------
1 | sujith | sujith#sujith
2 | mark |
3 | naveen | naveen#naveen
and supplier_contacts table, like this:
suppliers_id | name | email
-- | ---- |
1 | sujith | sujith1#sujith
2 | user1 | user1#user1
2 | user2 | user2#user2
3 | naveen1 | naveen1#naveen1
3 | naveen | naveen2#naveen
And I want to get something like this:
contacts_name | name | email
-- | ------ | -------
sujith | sujith | sujith#sujith
sujith | sujith | sujith1#sujith
user1 | user1 | user1#user1
user2 | user2 | user2#user2
naveen | | naveen#naveen
naveen1 | naveen1 | naveen1#naveen1
naveen | naveen | naveen2#naveen
All the email id should come in one Column from both the tables.
I tried the query below:
SELECT
suppliers.name,
supplier_contacts.name AS name1,
supplier_contacts.email AS sup_c_email
FROM suppliers
JOIN supplier_contacts
ON suppliers.id = supplier_contacts.suppliers_id
Can anyone help me on this? Basically i want the emails from both the tables to come under one column also should show contacts_name and name from both the tables. If any name or contacts_name is NULL also its fine.
SELECT suppliers.name, supplier_contacts.name AS name1, supplier_contacts.email AS
sup_c_email
FROM supplier
INNER JOIN suppliers_contacts
ON suppliers.email = supplier_contacts.email
I hope this will help you
I think what you are looking for is a full outer join
Although it returns large result-sets.
Great read at this link
SELECT s.contacts_name , sc.name , sc.email
FROM supplier as s
JOIN suppliers_contacts as sc
ON s.id = sc.suppliers_id
For more explainations visit below link hope you get help from it
https://www.tutorialspoint.com/mysql/mysql-using-joins.htm
You could use union for your case, first get list of all emails the then do a left join
with suppliers_contacts
select
t.contacts_name,
s.name,
t.email
from (
select contacts_name, email from suppliers where email is not null
union
select name, email from suppliers_contacts
) t
left join suppliers_contacts s on t.email = s.email
order by t.contacts_name;
Demo
As per your last comment The resultset am expecting is email list. It should merge the email list from two tables and show in one column, you can simply use union query
select contacts_name, email from suppliers where email is not null
union
select name contacts_name, email from suppliers_contacts
order by contacts_name;
Demo
Edit * I want to show all the email address from both the tables with the contacts_name and name from each table. If names are NULL its fine*
select
t.contacts_name,
sc.name supplier_contact_name,
s.contacts_name supplier_name,
t.email
from (
select contacts_name, email from suppliers where email is not null
union
select name, email from suppliers_contacts
) t
left join suppliers_contacts sc on t.email = sc.email
left join suppliers s on t.email = s.email
order by t.contacts_name;
Demo
I have two tables, for simplicity, table A and table B (Note, I don't have the authority to change the structure of these tables, so I'm asking this question to get around a bad database design).
Table A has two columns:
"id" - is the unique identifier.
"customer_id" - is the customer's ID.
So table A holds a list of customer IDs.
Table B holds properties about customers. But it does it in a weird way (again, I didn't set this up, and I can't change it). Table B has [NUMBER] columns:
"id" - is the unique identifier.
"customer_id" - is the customer's ID.
"key" - is the name of the key/value pair
"value" - is the value of the key/value pair
So table B holds key/value pairs that are linked to customers by their ID.
I could join these two tables to get something like this:
+----+-------------+------------+-------+
| id | customer_id | key | value |
+----+-------------+------------+-------+
| 0 | 5 | first_name | Bob |
| 1 | 5 | last_name | Jones |
| 2 | 6 | first_name | Sally |
| 3 | 6 | last_name | Sue |
+----+-------------+------------+-------+
But as you can see, that can be difficult to manage because information about one customer is on two different rows. What would be ideal is something like this:
+----+-------------+------------+-----------+
| id | customer_id | first_name | last_name |
+----+-------------+------------+-----------+
| 0 | 5 | Bob | Jones |
| 1 | 6 | Sally | Sue |
+----+-------------+------------+-----------+
With all of the customer's data on one row.
Is there a way to do this in a SQL query so that I don't have to mess with the results in PHP? Or will I have to pick through the data in PHP?
Given that you cannot alter the table structure, one approach is to use subselects on the customer_id and key:
SELECT
tableA.id,
tableA.customer_id,
(
SELECT
tableB.`value`
FROM tableB
WHERE tableB.customer_id = tableA.customer_id
AND tableB.`key` = 'first_name'
) AS first_name,
(
SELECT
tableB.`value`
FROM tableB
WHERE tableB.customer_id = tableA.customer_id
AND tableB.`key` = 'last_name'
) AS last_name
FROM tableA
Note: Performance-wise this query might suck. But, if you are out of options, maybe the slow query will drive the people who make decisions to allow the structure to be changed.
Use Group_concat or Group by
Select *,Group_concat(value) as full_name
From b left join a on b.customer_id=a.customer_id
Group by customer_id
One method is conditional aggregation:
select (#rn := #rn + 1) as id, customer_id,
max(case when `key` = 'first_name' then value end) as first_name,
max(case when `key` = 'last_name' then value end) as last_name
from b cross join
(select #rn := 0) params
group by customer_id;
I'm not sure what table a would be used for, perhaps for filtering the customer ids.
This will do what you want:
SELECT A.customer_id, B.value, B_1.value
FROM (A INNER JOIN B ON A.customer_id = B.customer_id)
INNER JOIN B AS B_1 ON B.customer_id = B_1.customer_id
WHERE (((B.key)="first_name") AND ((B_1.key)="last_name"));
I'm making a search function in PHP and I have three tables that I wish to join to a single one; the three tables looks as follow:
band
ID | bands
---+----------
1 | Muse
2 | Coldplay
3 | etc.
release
ID | releases
---+----------
1 | Showbiz
2 | Origin of Symmentry
3 | etc.
track
ID | tracks
---+-----------
1 | Sunburn
2 | Muscle Museum
3 | etc.
I want these tables to be put into this:
discografic
ID | band_id | release_id | track_id
---+----------+-------------+---------
1 | 1 | 1 | 1
2 | 1 | 1 | 2
3 | etc.
So that the table with the SQL code looks like this:
discografic
ID | bands | releases | tracks
---+----------+-------------+---------
1 | Muse | Showbiz | Sunburn
2 | Muse | Showbiz | Muscle Museum
3 | etc.
I want to INNER JOIN these tables. I joined one but I can't really figure out how the get the last joined as well.
SELECT *
FROM band
INNER JOIN discografic
ON band.id = discografic.band_id
This should probably have its own question; I also want to be able to search this database, but only have the result show up once, and also reference to the band every time. For example, if I search "Showbiz" it will give me "Muse", and only show it once.
Note: This is for testing purposes only, security is none of my concerns.
Try with this query:
select d.id,b.bands,r.releases,t.tracks from discografic as d INNER JOIN band as b on
d.band_id=b.id INNER JOIN release as r on d.release_id=r.id INNER JOIN track as t on
d.track_id=t.id GROUP BY d.id
Try This query
Select a.ID,b.bands,c.releases,d.tracks from discografic as a
inner join band as b on a.band_id = b.ID
inner join release as c on a.release_id = c.ID
inner join track as d on a.track_id = d.ID
where b.bands = 'Muse'
Use this query to insert the data like you wanted:
Insert into discograpy
(id,bands,releases,tracks)
SELECT band.ID,bands,releases,tracks
FROM band
INNER JOIN releases
ON band.id = releases.id
inner join track
on band.id = track.id
Use this query to show you only one band:
Declare #releases varchar(50)
Set #releases = 'showbiz'
SElect distinct bands from discograpy where releases = #releases
Here any variable can be passed or set in place of showbiz. This is an example
I have two tables in MySQL:
Table entry:
id | name | date
1 | Test Entry | 12/12/2013
2 | Test Entry 2 | 12/12/2013
Table note
id | entry_id | name | value
1 | 1 | note1 | value1
2 | 1 | note2 | value2
3 | 2 | note1 | value1
4 | 3 | note4 | value4
Where entry_id in note is a foreign key to id in entry.
Is there any solution I can create with a SELECT that will give me a result like the following?
entry_id | name | note1 | note2 | note3
1 | Test Entry | value1 | value2 | -
2 | Test Entry 2 | value 1 | - | value3
I want to avoid LEFT JOIN here (current implementation is working like this) and want to join note only once if that is possible. LEFT JOIN is not good here, because I do not know how many notes can be attached to one entry. My current implementation works that way that I first fetch all distinct notes by name that can be found in note, and then build a SELECT with foreach through PHP. Finally, the SELECT statement looks like this:
SELECT
E.id as entry_id,
E.name as name,
N1.value as note1_value,
N2.value as note2_value,
N3.value as note3_value
FROM entry E
JOIN LEFT note N1 ON E.id = N1.entry_id AND N1.name = 'note1'
JOIN LEFT note N2 ON E.id = N2.entry_id AND N2.name = 'note2'
JOIN LEFT note N3 ON E.id = N3.entry_id AND N3.name = 'note3'
Things get tricky when I join on note 20-30 times.
No, there is not a way to do that without joins.
I would recommend doing 2 queries.
select * from entry where id = id
select * from note where entry_id = id
and then join the results in your application code. You're right, the left joins are going to be bad.
Best would be to use a table with one note value and a note type (number) per each line.
id | value | note_no
Like this you can use as much notes as you like.
You can get the notes on one line using group_concat.
For an example, see here: http://lietoservetruth.wordpress.com/2010/12/13/mysql-group_concat-vertival-concat-concat-records/
This is faster than asking DB twice, and it's better DB design...