Join two tables and show Columns of one table as Rows - sql-server-2008

There are two tables which I have to join and produce the expected result
Employee Table
EmpID | EmpName
1 | Adam
2 | Eve
3 | John
4 | Steve
EmployeeNationality Table
EmpID | Nationality
1 | US
1 | UK
1 | UKraine
2 | US
3 | Canada
4 | Spain
Result Expected
EmpID | EmpName | Nationality1 | Nationality2
1 | Adam | US | UK
2 | Eve | US |
3 | John | Canada |
4 | Steve | Spain |
Though there are three records for Employee ID 1 (Adam) I always have to show only two Nationality so the no of columns are fixed.
Thanks in advance

If you just need two nationalities:
WITH CTE AS(
SELECT e.EmpID,
e.EmpName,
en.Nationality,
RN = ROW_NUMBER() OVER (PARTITION BY e.EmpID,e.EmpName
ORDER BY e.EmpID)
FROM dbo.employee e
INNER JOIN employeenationality en
ON e.empid = en.empid
)
SELECT DISTINCT c1.EmpID, c1.EmpName,
Nationality1 = (SELECT Nationality FROM CTE Nationality1
WHERE c1.EmpID = Nationality1.EmpID
AND Nationality1.RN = 1),
Nationality2 = (SELECT Nationality FROM CTE Nationality2
WHERE c1.EmpID = Nationality2.EmpID
AND Nationality2.RN = 2)
FROM CTE c1
Sql-Fiddle
Otherwise use PIVOT.

Related

Group and join two tables based on id?

I have a mysql table that looks something like this:
id | name
---+-------
1 | cola
2 | pepsi
3 | sprite
and another table:
customer | buy1 | buy2
---------+------+-----
Jhon | 2 | 3
Alice | 1 | 3
Tony | 3 | 2
I want to join the two tables and generate
customer | buy1 | buy2
---------+-------+--------
Jhon | Pepsi | Sprite
Alice | Cola | Sprite
Tony | Sprite| Pepsi
SELECT C.customer, REF.NAME, REF2.NAME
FROM OTHER_TABLE AS C
JOIN TABLE_SOMETHING_LIKE_THIS AS REF ON C.BUY1 = REF.ID
JOIN TABLE_SOMETHING_LIKE_THIS AS REF2 ON C.BUY2 = REF2.ID
You can write subqueries in a select list like this:
select
customer,
(select name from tbl1 where id = buy1) buy1,
(select name from tbl1 where id = buy2) buy2
from
tbl2;

How to find the maximum of a group with multiple maximas in sql?

The table must be grouped by department and the maximum amount of the department must be returned
Table A:
Id
Name
Department
1
John Abraham
HR
2
Michael Clarke
HR
3
Roy Thomas
Manager
4
Tom Jose
HR
4
Jerry Pinto
Manager
Table B:
M_Id
Amount
1
5000
2
5000
3
2500
4
1000
4
1500
Expected Answer
Id
Name
Department
Amount
1
John Abraham
HR
5000
2
Michael Clarke
HR
5000
3
Roy Thomas
Manager
2500
You can try something like this:
select main.*
FROM
-- get all information from t1 and amount from t2
(
select t1.*, t2.amount from t1 inner join t2 on t1.id = m_id
) main
INNER JOIN
-- get max amount by department
(
select department, max(amount) max_amount from t1 inner join t2 on t1.id = m_id
group by department
) summary
-- match with main by department and the max amount
on main.department = summary.department
and main.amount = summary.max_amount;
Result
+------+----------------+------------+--------+
| id | name | department | amount |
+------+----------------+------------+--------+
| 1 | John Abraham | HR | 5000 |
| 2 | Michael Clarke | HR | 5000 |
| 3 | Roy Thomas | Manager | 2500 |
+------+----------------+------------+--------+
Example is here: https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=a4cdd94b415df204b0fd967263ba9dc8
Explanation
Since you want to get max amount by department, we created a subquery for that. We gave it an alias summary. That gave us this:
select department, max(amount)
from t1 inner join t2 on t1.id = m_id group by department;
+------------+-------------+
| department | max(amount) |
+------------+-------------+
| HR | 5000 |
| Manager | 2500 |
+------------+-------------+
We combined data that you wanted to report on by combining t1 and t2 tables and gave it an alias main. That gave us this:
select t1.*, t2.amount from t1 inner join t2 on t1.id = m_id;
+------+----------------+------------+--------+
| id | name | department | amount |
+------+----------------+------------+--------+
| 1 | John Abraham | HR | 5000 | <-- want this
| 2 | Michael Clarke | HR | 5000 | <-- want this
| 3 | Roy Thomas | Manager | 2500 | <-- want this
| 4 | Jerry Pinto | Manager | 1000 |
| 4 | Tom Jose | HR | 1000 |
+------+----------------+------------+--------+
We, then, ensured that both subqueries were joined based on the department and the amounts in both subqueries.

How we get multiple column count(TOP) using MySQL single query?

I have a table structure like:
id | ex_name | att_name
10 | David | sam G&G
12 | John | mark hol
13 | John | john b
14 | Mark | john c
15 | David | mark hol
16 | David | mark hol
17 | Mark | sam G&G
18 | John | john b
19 | David | sam G&G
20 | John | sam G&G
When I'm using below query:
SELECT att_name
, count(att_name) as att_count
FROM `tablename`
group
by att_name
order
by att_count desc
Returns:
sam G&G = 4
mark hol = 3
john b = 2
john c = 1
I want top values of output i.e
sam G&G which is 4
Same with column ex_name it returns:
David = 4
john = 4
mark = 2
I want top values of the ex_name column which is David and John having count 4
What I want the final output like :
ex_name | att_name | ex_count | att_count
David Sam G&G 4 4
John 4
I'm also tried below query to fetch the output but in this case, I get ex_name and att_name is NULL.
SELECT a.att_name,b.att_name,max(a.ex_count),max(b.att_count)
FROM application_data
INNER JOIN (
SELECT ex_name,count(ex_name) as ex_count
FROM application_data
GROUP BY ex_name
) a
INNER JOIN (
SELECT att_name ,count(att_name) as att_count
FROM application_data
GROUP BY att_count
) b
It returns:
ex_name | att_name | ex_count | att_count
NULL NULL 4 4
Can you help me out?Thanks in advance
It appears that you want to aggregate your table by some column, and then retain all group records which share the highest count. One way to do this is to add a HAVING clause to your current query which asserts that the count for a group to be retained is the highest count from all groups.
SELECT att_name, COUNT(*) AS cnt
FROM tablename
GROUP BY att_name
HAVING COUNT(*) = (SELECT COUNT(*) FROM tablename
GROUP BY att_name ORDER BY COUNT(*) DESC LIMIT 1);
Demo

Mysql query to get max age by section and if two or more has same age return student with smallest id

I have a table of students with temporary test values like this:
Table students
+----+-------------+-------+-----------+
| id | section_id | age | name |
+----+-------------+-------+-----------+
| 1 | 1 | 18 | Justin |
+----+-------------+-------+-----------+
| 2 | 2 | 14 | Jillian |
+----+-------------+-------+-----------+
| 3 | 2 | 16 | Cherry |
+----+-------------+-------+-----------+
| 4 | 3 | 19 | Ronald |
+----+-------------+-------+-----------+
| 5 | 3 | 21 | Marie |
+----+-------------+-------+-----------+
| 6 | 3 | 21 | Arthur |
+----+-------------+-------+-----------+
I want to query the table such that I want to get all the maximum ages of each section. However, if two students have the same age, the table produced will return the student with smallest id.
Return:
+----+------------+-----+--------+
| id | section_id | age | name |
+----+------------+-----+--------+
| 1 | 1 | 18 | Justin |
+----+------------+-----+--------+
| 3 | 2 | 16 | Cherry |
+----+------------+-----+--------+
| 5 | 3 | 21 | Marie |
+----+------------+-----+--------+
I tried this query:
SELECT ANY_VALUE(id), ANY_VALUE(section_id), MAX(age), ANY_VALUE(name) FROM
(SELECT id, section_id, age, name FROM students ORDER BY id) as X
GROUP BY section_id
Unfortunately, there are instances that id does not match the age and name.
I have on my end:
sql_mode = only_full_group_by
and I don't have a privilege to edit that, hence the any_value function but I have no idea how to use it.
This will do what you want.
It starts by finding the maximum age per section (including duplicates).
Then it joins those results with the minimum id per section (to eliminate duplicates).
And finally, select all fields for the matching id and section combinations.
SELECT s3.*
FROM students s3
INNER JOIN (
SELECT MIN(s2.id) AS id, s2.section_id
FROM students s2
INNER JOIN (
SELECT s1.section_id, MAX(s1.age) AS age
FROM students s1
GROUP BY s1.section_id
) s1 USING (section_id, age)
GROUP BY s2.section_id
) s2 USING (id, section_id);
Working SQL fiddle: https://www.db-fiddle.com/f/aezgAYM6A5KnXykceB7At1/0
I would simply use a correlated subquery:
select s.*
from students s
where s.id = (select s2.id
from students s2
where s2.section_id = s.section_id
order by s2.age desc, s2.id asc
limit 1
);
This is pretty much the simplest way to express the logic. And with an index on students(section, age, id), it should be the most performant as well.

mySQL JOIN of several tables

I do have the following three tables in a MySQL-DB (InnoDB)
UserTab
ID | Name | ---
------------------
1 | Tom |
2 | Dick |
3 | Harry |
EventTab
ID | Name | ---
------------------
1 | Easter |
2 | Holidays |
3 | ThxGiving |
4 | Christmas |
ParticipationTab
ID | UserID | EventID
---------------------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 1
5 | 2 | 4
6 | 3 | 3
And I want to achieve the follwing result with my query:
QueryResultTab
UserTab.Name | EventTab.Name | NoPart | Names
-----------------------------------------------
Tom | Easter | 2 | Tom, Dick
Tom | Holidays | 1 | Tom
Tom | ThxGiving | 2 | Tom, Harry
Dick | Easter | 2 | Tom, Dick
Dick | Christmas | 1 | Dick
Harry | ThxGiving | 2 | Tom, Harry
I do know about Count() combined with GROUP to get the number of participants
I know about group-concat to get the "Names".
SELECT Event, GROUP_CONCAT(Name ORDER BY Name ASC SEPARATOR ', ') as Names
FROM
(SELECT ID as UserID, Name FROM X_Users WHERE ConditionA) AS UserTab
INNER JOIN
(SELECT EventID, UserID FROM X_Participation WHERE ConditionB) AS ParticipationTab
ON UserTab.UserID = ParticipationTab.UserID
INNER JOIN
(SELECT ID as EventID, Event FROM X_Events WHERE ConditionC) AS EventTab
ON ParticipationTab.EventID = EventTab.EventID
GROUP BY EventTab.EventID
This gives me:
ConcatTab
EventTab.Name | Names
---------------------------
Easter | Tom, Dick
Holidays | Tom
ThxGiving | Tom, Harry
Easter | Tom, Dick
Christmas | Dick
ThxGiving | Tom, Harry
I know about JOINs as you can see. Probably I could use LEFT or RIGHT JOINs as well for this.
For the other parts I use this query:
SELECT Name, Event, NoPart
FROM (SELECT ID as UserID, Name FROM X_Users WHERE ConditionA) AS UserTab
INNER JOIN (SELECT EventID, UserID FROM X_Participation WHERE ConditionB) AS PartTab
ON UserTab.UserID = PartTab.UserID
INNER JOIN (SELECT ID as EventID, Event FROM X_Events WHERE ConditionC) AS EvTab
ON PartTab.EventID = EvTab.EventID
INNER JOIN (SELECT EventID as CntID, COUNT(*) AS NoPart FROM X_Participation WHERE ConditionB) AS CntTab
ON EvTab.EventID = CntTab.CntID
ORDER BY UserTab.UserID
This gives me:
CountTab
UserTab.Name | EventTab.Name | NoPart
--------------------------------------
Tom | Easter | 2
Tom | Holidays | 1
Tom | ThxGiving | 2
Dick | Easter | 2
Dick | Christmas | 1
Harry | ThxGiving | 2
But how to combine/merge ConcatTab and CountTab into QueryResultTab? I want to retrieve the result table in PHP row by row with mysql_fetch_assco().
Please don't tell me about PDO, etc. I know about it.
The other option - what I try to avoid - is do it within a PHP-loop and use numerous tiny SQL-queries to achieve the result.
Based on your sample data, you want all the rows in the participation table, with information from the dimensions. Then you want a summary of that table.
Here is an approach that uses a subquery in the FROM clause:
SELECT u.name, e.name, p2.numPart, p2.Names
FROM X_Participation p INNER JOIN
X_Users u
ON u.UserID = p.UserID INNER JOIN
X_Events e
ON p.EventID = e.EventID INNER JOIN
(SELECT p2.EventId, COUNT(*) as numPart,
GROUP_CONCAT(u2.name SEPARATOR ', ') as names
FROM X_Participation p2 INNER JOIN
X_Users u2
ON u2.UserID = p2.UserID
GROUP BY p2.EventId
) p2
ON p2.EventId = p.EventId;
Notes:
If you are going to use table aliases (which you should), make them shorter, not longer than the table names.
Don't use subqueries unnecessarily. This is especially true in MySQL which materializes subqueries.
You can put additional conditions in a WHERE clause of the outer query.