How to join 2 rows from the tables? - mysql

Hi I have a table here with the follow columns: ApplicantID, Name and Age. I would like to know how to join the 2 rows of applicant together to be displayed on the same table(php). I am trying to retrieve it from database. Thanks!
--------------------------------------
Applicant ID Name Age
--------------------------------------
001 John 20
002 Nick 22
Below is what I want it to return
--------------------------------------
Name1 Age1 Name2 Age2
--------------------------------------
John 20 Nick 22
EDIT: The code from Amit work, but the data returned is:
Name1 Age1 Name2 Age2
--------------------------------------
John 20 Nick 22
--------------------------------------
Nick 22 Judy 25
How do I only return Nick once?

if you're using php, it could be like this :
let's assume that we have an array which have same value as your table.
$arr = [
['Applicant ID' => 001, 'Name' => 'John', 'Age' => 20],
['Applicant ID' => 002, 'Name' => 'Nick', 'Age' => 22],
];
$res = [];
foreach($arr as $key => $values){
$names = 'Name'.($key+1);
$ages = 'Age'.($key+1);
$res[$names] = $values['Name'];
$res[$ages] = $values['Age'];
}

you could use a cross (self) join filtering the rows
select a.name as name1, a.age as age1, b.name as name2, b.age as age2
from table1 as a
cross join table2 as b
where a.applicant_ID = '001'
and b.applicant_ID ='002'

You can use self join by using following query:-
SELECT applicant1.name,
applicant1.age,
applicant2.name,
applicant2.age
FROM applicant as applicant1
JOIN applicant applicant2
on applicant1.applicant_id+1 = applicant2.applicant_id;

Related

Joining two tables in laravel - how to have second table data as a property of result

I have two tables A and B.
Table A:
no name type
1 shoe 1
2 shirt 2
3 book 3
Table B:
type color size
1 red big
2 yellow small
3 blue medium
When I query where A.no === 1 and A.type === 1, I want to get data like:
{
no: 1,
name: 'shoe',
type: 1,
info: {
color: 'red',
size: 'big'
},
}
I tried something like this:
select a.*, b.* from stores a, types b where a.type = 1 and a.type = b.id
and it returns only plain object, I want to get nested data like the above.
I think it can be done using join and doing any other query tricks.
Here's the sql fiddle link I prepared for you.
http://sqlfiddle.com/#!9/3ad910/2
Thanks in advance.
Model TableA:
public function info()
{
return $this->hasOne(TableB::class, 'type', 'type');
}
Model TableB:
public function tableA()
{
return $this->belongsTo(TableA::class, 'type', 'type');
}
The Query:
TableA::with('info')->where(['type' => 1, 'no' => 1])->get();
So the query that you have (although better written using post-1992 query syntax) is all that you need. The rest of the problem is a simple case of rearranging the resulting array. I don't know eloquent/laravel, and I'm embarrassingly bad at rearranging arrays, but here's an example of the kind of thing I mean using plain old php (perhaps someone will be kind enough to write a more apt array transformation)...
<?php
/*
DROP TABLE IF EXISTS table_a;
CREATE TABLE table_a
(no SERIAL PRIMARY KEY
,name VARCHAR(12) UNIQUE
,type INT NOT NULL
);
INSERT INTO table_a VALUES
(1,'shoe',1),
(2,'shirt',2),
(3,'book',3);
DROP TABLE IF EXISTS table_b;
CREATE TABLE table_b
(type SERIAL PRIMARY KEY
,color VARCHAR(12) NOT NULL
,size VARCHAR(12) NOT NULL
);
INSERT INTO table_b VALUES
(1,'red','big'),
(2,'yellow','small'),
(3,'blue','medium');
SELECT a.no
, a.name
, b.*
FROM table_a a
JOIN table_b b
ON b.type = a.type
ORDER
BY a.no;
+----+-------+------+--------+--------+
| no | name | type | color | size |
+----+-------+------+--------+--------+
| 1 | shoe | 1 | red | big |
| 2 | shirt | 2 | yellow | small |
| 3 | book | 3 | blue | medium |
+----+-------+------+--------+--------+
*/
require('path/to/connection/stateme.nts');
$query = "
SELECT a.no
, a.name
, b.type
, b.color
, b.size
FROM table_a a
JOIN table_b b
ON b.type = a.type
WHERE a.no = 1
AND a.type = 1
ORDER
BY a.no;
";
$result = mysqli_query($db,$query) or die(mysqli_error());
$old_array = array();
while($row = mysqli_fetch_assoc($result)){
$old_array[] = $row;
}
$new_array = array();
foreach ($old_array as $row) {
$new_array[]['name'] = $row['name'];
$new_array[$row['no']]['info']['color'] = $row['color'];
$new_array[$row['no']]['info']['size'] = $row['size'];
}
$new_array = array_values($new_array); // reindex
print_r($new_array);
?>
Outputs:
Array
(
[0] => Array
(
[name] => shoe
)
[1] => Array
(
[info] => Array
(
[color] => red
[size] => big
)
)
)
or, json_encoded...
[{"name":"shoe"},{"info":{"color":"red","size":"big"}}]

$wpdb->get_results query returns different (wrong) results compared to phpmyadmin

I have 4 custom tables in my database - wp_api_teams, wp_api_matches, wp_api_competitions and wp_api_federations. They are part of my Wordpress database, this is how they look (I'm using foreign keys and all of that):
I am trying to output all the teams that are part of a federation. When I run this in phpmyadmin it works:
SELECT
wp_api_teams.team_id,
wp_api_teams.title,
wp_api_competitions.comp_id,
wp_api_competitions.title,
wp_api_federations.federation_id,
wp_api_federations.title
FROM
wp_api_teams
JOIN wp_api_matches
ON wp_api_teams.team_id = wp_api_matches.hometeam_id OR wp_api_teams.team_id = wp_api_matches.awayteam_id
JOIN wp_api_competitions
ON wp_api_matches.comp_id = wp_api_competitions.comp_id
JOIN wp_api_federations
ON wp_api_competitions.federation_id = wp_api_federations.federation_id
WHERE wp_api_federations.federation_id = 1
GROUP BY (wp_api_teams.team_id);
I get the exact results that I am looking for.
-----------------------------------------------------------------------------------
| team_id | title | comp_id | title | federation_id | title |
1 Arsenal 1 Premier League 1 England
2 Chelsea 1 Premier League 1 England
3 Liverpool 1 Premier League 1 England
4 Manchester United 1 Premier League 1 England
5 Manchester City 1 Premier League 1 England
This is the code I'm using in Wordpress:
global $wpdb;
$sql = "
SELECT
wp_api_teams.team_id,
wp_api_teams.title,
wp_api_competitions.comp_id,
wp_api_competitions.title,
wp_api_federations.federation_id,
wp_api_federations.title
FROM
wp_api_teams
JOIN wp_api_matches
ON wp_api_teams.team_id = wp_api_matches.hometeam_id OR wp_api_teams.team_id = wp_api_matches.awayteam_id
JOIN wp_api_competitions
ON wp_api_matches.comp_id = wp_api_competitions.comp_id
JOIN wp_api_federations
ON wp_api_competitions.federation_id = wp_api_federations.federation_id
WHERE wp_api_federations.federation_id = 1
GROUP BY wp_api_teams.team_id
";
$test = $wpdb->get_results($sql);
echo('<pre>');
print_r($test);
echo('</pre>');
and the result that I'm getting is missing two table columns:
Array
(
[0] => stdClass Object
(
[team_id] => 1
[title] => England
[comp_id] => 1
[federation_id] => 1
)
[1] => stdClass Object
(
[team_id] => 2
[title] => England
[comp_id] => 1
[federation_id] => 1
)
.... and so on.
As you can see, the wp_api_teams.title and wp_api_competitions.title columns are missing from the result.
So my questions is, why is this happening, why are these columns being omitted and is there anything I can do to fix this, because I absolutely need them in my returned result. How can the same query produce a different result in WP vs PHPmyadmin.
Is this a known bug or is there something wrong with my code?
I'm running 10.2.14-MariaDB on localhost and all the table engines are InnoDB.
Your column names are the same in your result set. You need to provide an alias:
global $wpdb;
$sql = "
SELECT
wp_api_teams.team_id,
wp_api_teams.title as team_title,
wp_api_competitions.comp_id,
wp_api_competitions.title as competition_title,
wp_api_federations.federation_id,
wp_api_federations.title as federation_title
FROM
wp_api_teams
JOIN wp_api_matches
ON wp_api_teams.team_id = wp_api_matches.hometeam_id OR wp_api_teams.team_id = wp_api_matches.awayteam_id
JOIN wp_api_competitions
ON wp_api_matches.comp_id = wp_api_competitions.comp_id
JOIN wp_api_federations
ON wp_api_competitions.federation_id = wp_api_federations.federation_id
WHERE wp_api_federations.federation_id = 1
GROUP BY wp_api_teams.team_id
";
$test = $wpdb->get_results($sql);
echo('<pre>');
print_r($test);
echo('</pre>');

mysql ColumnName AS 1, ColumnName AS 2, with WHERE, using UNION for all columns get AS 1

Have table like this
IdRows | UpperLevelIdRows | CategoriesName |
-------------------------------------------------
2 | 0 | Transport
4 | 2 | Cars
12 | 4 | Alfa Romeo
Query
SELECT IdRows AS IdRows1, CategoriesName AS CategoriesName1 FROM categories
WHERE UpperLevelIdRows = ?
UNION
SELECT IdRows AS IdRows2, CategoriesName AS CategoriesName2 FROM categories
WHERE UpperLevelIdRows = ?
Data for placeholders is
Array
(
[0] => 2
[1] => 4
)
So
SELECT IdRows AS IdRows1 .... WHERE UpperLevelIdRows = 2
and
SELECT IdRows AS IdRows2 .... WHERE UpperLevelIdRows = 4
As result expect get array like
[0] => Array
(
[IdRows1] => 4
[CategoriesName1] => Cars
)
[1] => Array
(
[IdRows2] => 12
[CategoriesName2] => Alfa Romeo
)
But get array like this
[0] => Array
(
[IdRows1] => 4
[CategoriesName1] => Cars
)
[1] => Array
(
[IdRows1] => 12
[CategoriesName1] => Alfa Romeo
)
Instead of IdRows2 see IdRows1
If i execute only the second SELECT IdRows AS IdRows2 ..., then see as expected [CategoriesName2] => Alfa Romeo
Where is my mistake? What need to correct?
From the data i want to create select/option boxes. Like
First select box
echo '<select name="upper_level_id0" id="upper_level_id0" >
<option value="'.$IdRows1.'">'.$CategoriesName1.'</option>
</select>';
Second select box
echo '<select name="upper_level_id1" id="upper_level_id1" >
<option value="'.$IdRows2.'">'.$CategoriesName2.'</option>
</select>';
At the moment found solution using transaction. Loop through all SELECT ...
$db->beginTransaction();
foreach ( $sql_get_id_name as $k_sql => $val_sql ) {
$stmt_get_id_name = $db->prepare( $val_sql );
$stmt_get_id_name->execute( array( $data_get_id_name[$k_sql] ) );
$id_name[] = $stmt_get_id_name->fetchAll(PDO::FETCH_ASSOC);
}
$roll_back = $db->rollBack();
Use this select
select cp.IdRows p_id, cp.UpperLevelIdRows p_parent_id, cp.CategoriesName p_name,
cc.IdRows p_id, cc.UpperLevelIdRows c_parent_id, cc.CategoriesName c_name
from categories cc left join categories cp on cp.IdRows = cc.UpperLevelIdRows
where cc.UpperLevelIdRows = 4
This way you will get all the sons of a parent. The first 3 columns from the result are the parent (in your row data it will be the Cars) and the second its childs (in your row data the Alfa Romeo)

SQL: GROUP BY after JOIN without overriding rows?

I have a table of basketball leagues, a table af teams and a table of players like this:
LEAGUES
ID | NAME |
------------------
1 | NBA |
2 | ABA |
TEAMS:
ID | NAME | LEAGUE_ID
------------------------------
20 | BULLS | 1
21 | KNICKS | 2
PLAYERS:
ID | TEAM_ID | FIRST_NAME | LAST_NAME |
---------------------------------------------
1 | 21 | John | Starks |
2 | 21 | Patrick | Ewing |
Given a League ID, I would like to retrieve all the players' names and their team ID from all the teams in that league, so I do this:
SELECT t.id AS team_id, p.id AS player_id, p.first_name, p.last_name
FROM teams AS t
JOIN players AS p ON p.team_id = t.id
WHERE t.league_id = 1
which returns:
[0] => stdClass Object
(
[team_id] => 21
[player_id] => 1
[first_name] => John
[last_name] => Starks
)
[1] => stdClass Object
(
[team_id] => 21
[player_id] => 2
[first_name] => Patrick
[last_name] => Ewing
)
+ around 500 more objects...
Since I will use this result to populate a dropdown menu for each team containing each team's list of players, I would like to group my result by team ID, so the loop to create these dropdowns will only have to cycle through each team ID instead of all 500+ players each time.
But when I use the GROUP BY like this:
SELECT t.id AS team_id, p.id AS player_id, p.first_name, p.last_name
FROM teams AS t
JOIN players AS p ON p.team_id = t.id
WHERE t.league_id = 1
GROUP BY t.id
it only returns one player from each team like this, overriding all the other players on the same team because of the use of the same column names.
[0] => stdClass Object
(
[team_id] => 21
[player_id] => 2
[first_name] => Patrick
[last_name] => Ewing
)
[1] => stdClass Object
(
[team_id] => 22
[player_id] => 31
[first_name] => Shawn
[last_name] => Kemp
)
etc...
I would like to return something like this:
[0] => stdClass Object
(
[team_id] => 2
[player_id1] => 1
[first_name1] => John
[last_name1] => Starks
[player_id2] => 2
[first_name2] => Patrick
[last_name2] => Ewing
+10 more players from this team...
)
+25 more teams...
Is it possible somehow?
You cannot do this in SQL, since you cannot represent that result in a form of data set. You want to return complex object. What you can do, is to handle this in the code, and help yourself by returning a data set which is sorted by team_id. Whenever your team_id changes, then it is time to create new object in your code and fill it with new list of players.
It would be something like this (syntax might not be correct):
Returned result set:
team_id|player_id|first|last
1|1|f1|l1
1|2|f2|l2
1|3|f3|l3
2|5|f5|l5
2|6|f6|l6
And when this is returned in your code
$lastTeamId=0;
$output=array();
foreach($results as $row){
if($lastTeamId != $row["team_id"]){
$lastTeamId = $row["team_id"];
$output[$lastTeamId] = array();
}
$newPlayer = null;
$newPlayer->id = $row["player_id"];
$newPlayer->first = $row["first"];
$newPlayer->last = $row["last"];
$output[$lastTeamId][] = $newPlayer;
}
In MySQL, you could GROUP BY team_id and then SELECT GROUP_CONCAT(player detail ...). But that runs into restrictions and is not the typical relational approach.

Finding duplicate names where first name can be an initial or full name

I am trying to find duplicates by comparing the first name and surname columns in a table. The first name can be a name or an initial.
Reading other posts I have managed to figure out how to get the duplicate surnames and list the first letter for first name. But I am unsure how to only show rows where there is a match of surname and the first letter of the first name.
SELECT *
FROM table AS a
INNER JOIN (
SELECT LEFT( firstname, 1 ) , surname
FROM table
GROUP BY surname
HAVING COUNT( * ) > 1
) AS b ON a.surname = b.surname
id | firstname | surname
**************************
1 | joe | bloggs
2 | j | bloggs
3 | s | bloggs
4 | f | doe
5 | frank | spencer
Currently this query would return
1 | joe | bloggs
2 | j | bloggs
3 | s | bloggs
Result I would like would just contain the possible duplicates.
1 | joe | bloggs
2 | j | bloggs
I don't quite get what you want. Yor provided a query, your current table and the expected result.
I've just created your table, run your query and got the expected result. What is wrong with this?
SELECT FROM table1 AS a
INNER JOIN (
SELECT surname FROM table1
GROUP BY surname
HAVING COUNT(*) > 1
) AS b ON a.surname = b.surname
This effectively result in your expected result:
joe | bloggs
j | bloggs
Or am I missing something?
After re-reading... are you expecting to get only this?
j | bloggs
If that is the case, use this:
SELECT * FROM table1 AS a
INNER JOIN (
SELECT surname FROM table1
GROUP BY surname
HAVING COUNT(*) > 1
) AS b ON a.surname = b.surname
WHERE CHAR_LENGTH(firstname) = 1
Edit:
After the expected result was properly explained I conclude the query should be:
SELECT a.firstname, a.surname FROM t1 AS a
INNER JOIN (
SELECT LEFT(firstname, 1) AS firstChar, surname FROM t1
GROUP BY surname, firstChar
HAVING COUNT(surname) > 1
) AS b ON a.surname = b.surname AND b.firstChar = LEFT(a.firstname, 1)
Working example
You probably don't want to use initials all the time, e.g., if you always strip to initials you might consider Bob X the same as Bill X.
So you need to check three cases.
both firstnames are initials
both firstnames are non initials
only one firstname is an intial
So you can work with string methods of Mysql to check the length of either firstname and check the proper case.
I would join the table to itself like so:
select * into #temp from (
SELECT 1, 'joe', 'bloggs' UNION
SELECT 2, 'j', 'bloggs' UNION
SELECT 3, 'f', 'doe' UNION
SELECT 4, 'frank', 'spencer' UNION
SELECT 5, 'steven', 'woo' UNION
SELECT 6, 'steve', 'woo' UNION
SELECT 7, 'stanley', 'woo'
) x (id, firstname, surname)
select
*
from
#temp l
inner join
#temp r
on
left(l.firstname, 1) = left(r.firstname, 1)
and
l.surname = r.surname
where
l.id < r.id
drop table #temp
the downside to this is that the steven and stanley match. I would suggest you think about creating a firstname alias table and use that to standardize the firstnames.