MySQL Select Combined Unique - mysql

Table: Contacts
id | name | has_this
------------------------
1 | Jeff | 0
2 | Terry | 1
3 | Tom | 0
4 | Henry | 1
Table: has_thing
id | owner | thing
---------------------
1 | Terry | stuff
2 | Tom | stuff
3 | Toby | stuff
I want a SELECT that will return
name | thing
-------------
Terry | stuff
Tom | stuff
Henry |
Toby | stuff
Basically, I think I want a JOIN but I want any name that is in table 2(has_thing) that is not in table 1 to be included the output and any name that is in table 1(Contacts) WHERE has_this=1 to be included in the output

SELECT name, MAX(thing) as thing
FROM (SELECT c.name, h.thing
FROM Contacts AS c
JOIN has_thing AS h ON c.name = h.name
UNION
SELECT name, ''
FROM Contacts
WHERE has_thing = 1) AS subquery
GROUP BY name
MAX(thing) ensures that we pick up the non-empty thing from the first query when the contact has has_thing = 1.
You could also do it with LEFT JOIN:
SELECT c.name, IFNULL(h.thing, '') AS thing
FROM Contacts AS c
LEFT JOIN has_thing AS h ON c.name = h.name
WHERE c.has_thing = 1
OR h.name IS NOT NULL

Related

Case When Then Adjacent Switching Scenario Correspond to an ID

Let suppose
'Mary is a teacher in a middle school and she has a table seat storing students' names and their corresponding seat ids. The column id is a continuous increment. Mary wants to change seats for the adjacent students.'
The sample table looks like this:
+---------+---------+
| id | student |
+---------+---------+
| 1 | Doris |
| 2 | Abbot |
| 3 | Green |
| 4 | Emerson |
| 5 | Jeames |
+---------+---------+
Mary wants to switch Adjacent Student, the output looks like this:
+---------+---------+
| id | student |
+---------+---------+
| 1 | Abbot |
| 2 | Doris |
| 3 | Emerson |
| 4 | Green |
| 5 | Jeames |
+---------+---------+
I have come up with the solution using Case When and Then statement.
Solution :
SELECT
CASE
WHEN((SELECT MAX(id) FROM seat)%2 = 1) AND id = (SELECT MAX(id) FROM seat) THEN id
WHEN id%2 = 1 THEN id + 1
ELSE id - 1
END AS id, student
FROM seat
ORDER BY id
Is there any other easy way using case statement or any other approach through which we can solve this problem.
Thanks
You can use a combination of self join using LEFT JOIN, CASE WHEN and COALESCE as alternative.
select s1.id, coalesce(s2.student,s1.student)
from sample s1
left join sample s2
on s1.id + case when s1.id%2=1 then 1 else -1 end = s2.id
COALESCE and LEFT JOIN are just needed to keep the record for Jeames, which not join with s2
You can test on this db<>fiddle.
You can use lead() and first_value():
select id,
coalesce(lead(student) over (order by id),
first_value(student) over (order by id)
) as student
from t;

How do I join multiple entries in one table into a single relationship status in MySQL?

I have a table Follow, which only holds records of which UserID follows which TargetID.
If asked for user A:
If neither A or B are following eachother, they have status of 0 for unrelated, and aren't included in the results.
If user A is following B but not vice versa, B has status 1 for
being followed.
If user B is following A but not vice versa, B has
status 2 for being a follower.
If A is following B, and B following
A, B has status of 3 for being a friend.
How can I, in a single MySQL query, get the relationship status for a given user and all its relationships above status 0?
Example:
Users:
+----+-------+
| id | Name |
+----+-------+
| 1 | Bob |
| 2 | Steve |
| 3 | Scott |
| 4 | Mary |
+----+-------+
Follow:
+----+--------+----------+
| id | UserID | TargetID |
+----+--------+----------+
| 1 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 2 | 1 |
| 4 | 4 | 1 |
+----+--------+----------+
Expected result for user 1:
+----------+--------+-------+
| TargetID | Status | Name |
+----------+--------+-------+
| 2 | 3 | Steve | (friend)
| 3 | 1 | Scott | (following)
| 4 | 2 | Mary | (follower)
+----------+--------+-------+
You can use subqueries as illustrated below:
-- FOR USER 1
SELECT A.id TargetID,
SUM(IFNULL((SELECT 1 C FROM Follow B WHERE B.UserID=1 AND B.TargetID=A.id),0) +
IFNULL((SELECT 2 C FROM Follow D WHERE A.id=D.UserID AND D.TargetID=1), 0)) Status
, A.name
FROM (SELECT * FROM Users WHERE ID<>1) A
GROUP BY A.id, A.Name
HAVING Status>0; -- for a compact result
-- NOW GLOBALLY
SELECT A.UserID, A.id TargetID,
SUM(IFNULL((SELECT 1 C FROM Follow B WHERE B.UserID=A.UserID AND B.TargetID=A.id),0) +
IFNULL((SELECT 2 C FROM Follow D WHERE A.id=D.UserID AND D.TargetID=A.UserID), 0)) Status
, A.name
FROM (SELECT E.id UserID, F.* FROM Users E JOIN Users F ON E.id<>F.id) A
GROUP BY A.UserID, A.id, A.Name
HAVING Status>0 -- for a compact result
ORDER BY A.UserID;
See DEMO on SQL Fiddle
I have not tried this but try something among the lines of:
Select t.targetid as TargetId,
IF (
(select count(id) from follow where
follow.Userid = f.target.id and follow.target_id = u.id) > 1,
-- mean’s the target is following user 1
(IF (
(select count(id) from follow where
follow.Userid = u.id and follow.target_id = f.targetid) > 1, 3, 2))
-- if user1 is following aswell, then its a friend, else its a follower
, 1)
-- else means its a following
as status,
u.name as Name from follow f
inner Join users u on u.id = f.targetid
where u.id = 1
Inner join to select user 1's relations (if it doesn't exist, they aren't related)
If there is a record, means they are one of 3:

SQL-Query for a table with a foreign-key-field that references other foreign-key-fields

I have the following structure of tables in my database:
[table workers]
ID [PK] | worker | combined [FK]
--------+--------+--------------+
1 | John | 2
--------------------------------+
2 | Adam | 1
[table combined]
ID [PK] | name | helper [FK]
--------+----------------------+
1 | name1 | 1
2 | name2 | 2
[table helper]
ID [PK] | department [FK] | location [FK]
--------+-------------+-------------------
1 | 2 | 3
2 | 1 | 1
[table departments]
ID [PK] | department
--------+-------------+
1 | Development |
2 | Production |
[table location]
ID [PK] | department
--------+--------------+
1 | Paris |
2 | London |
3 | Berlin |
The table "workers" has an foreign-key-field ("combined"). The table "combined" has a field name and a foreign-key-field "helper" which again is a table with two foreign-key-fields.
My question is now, what is the simplest SQL-Query to get the following table:
[table workers]
ID [PK] | worker | combined-Name| department | location
--------+--------+--------------+------------+-----------
1 | John | name2 | Development| Paris
--------------------------------+------------+-----------
2 | Adam | name1 | Production | Berlin
I tried it already with some LEFT-JOINS but did not manage it to get all "clearnames" to the table "workers"
This query would work:
SELECT w.ID, worker, c.name AS `combined-Name`, d.department, l.department as
location FROM workers w
LEFT JOIN combined c ON c.ID = w.combined
LEFT JOIN helper h ON h.ID = c.helper
LEFT JOIN departments d ON d.ID = h.department
LEFT JOIN location l ON l.ID = h.location
GROUP BY w.ID
I used the AS keyword to set the names to your preferred output.
This was tested locally using the provided structures and data.
It's basically 4 simple left joins, and then instead of selecting the ID's I select the name columns of the foreign tables.
The alias on c.name is quoted because we need to escape the special character -
use following query:
select [workers].worker,[combined].name as combined-name,[departments].name as department,[location].name as location from [workers]
left join [combined] on [workers].combined = [combined].combined
left join [helper] on [helper].ID = [combined].helper
left join [departments] on [departments].ID = [helper].department
left join [location] on [location].ID = [helper].location

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.

Query two tables and replace values from one table in the second one

Say I have two tables like so:
fruits
-------------
id | name |
-------------
1 | Apple |
2 | Orange |
3 | Pear |
-------------
users
-------------------
id | name | fruit |
-------------------
1 | John | 3 |
2 | Bob | 2 |
3 | Adam | 1 |
-------------------
I would like to query both of those tables and in the result get user ID, his name and a fruit name (fruit ID in users table corresponds to the ID of the fruit) like so:
--------------------
id | name | fruit |
--------------------
1 | John | Pear |
2 | Bob | Orange |
3 | Adam | Apple |
-------------------
I tried joining those two with a query below with no success so far.
"SELECT * FROM users, fruits WHERE fruits.id = fruit"
Thanks in advance.
You need to JOIN the fruit table like this:
SELECT u.id, u.name, f.name FROM users u JOIN fruits f ON u.fruit = f.id
See a working example here
select a.id,a.name,b.name as fruit
from users a
join friuts b
on b.id=a.fruit
try this:
SELECT a.id, a.name, b.name FROM
users a JOIN fruits b
ON a.fruit = b.id
SELECT u.id, u.name, f.name
FROM users u
inner join fruits f
ON f.id = u.fruit