How to join mysql tables - sql

I've an old table like this:
user> id | name | address | comments
And now I've to create an "alias" table to allow some users to have an alias name for some reasons. I've created a new table 'user_alias' like this:
user_alias> name | user
But now I have a problem due my poor SQL level... How to join both tables to generate something like this:
1 | my_name | my_address | my_comments
1 | my_alias | my_address | my_comments
2 | other_name | other_address | other_comments
I mean, I want to make a "SELECT..." query that returns in the same format as the "user" table ALL users and ALL alias.. Something like this:
SELECT user.* FROM user LEFT JOIN user_alias ON `user`=`id`
but it doesn't work for me..

I think you need something like this:
SELECT user.*
FROM user
LEFT JOIN user_alias
ON user.name=user_alias.name
Your original query was not specific enough in the join condition.

Something like
SELECT user.name, user.address, user.comment FROM user
UNION ALL
SELECT user_alias.alias, user.address, user.comment
FROM user INNER JOIN user_alias on user.name = user_alias.name
ORDER BY name
will get you close to what you want.
You need to UNION two SELECTs together because the LEFT JOIN solution proposed by others will include only one row in the result set for users with aliases, not two as specified in your question.
But you should make the common column joining user and alias the id column, not the name column.

SELECT user.* FROM user LEFT JOIN user_alias ON user.name = user_alias.name

First of all - the query you want to build is not trivial, because you are trying to get some results spanned across more than one row. So I will offer you a proper solution in a fashion like it should be (read: in a way a database developer will do this :-).
First, you should modify your user_alias table so that it will contain id column but not the name. It is not good idea to join your tables using the name field. The reason for this is that there could be two Sarah Connors.
Then, you can get results from both tables using this query:
SELECT user.*, user_alias.*
FROM user LEFT JOIN user_alias
ON user.id=user_alias.id
This way you will get your results in such format:
id | name | address | comments | user
-------------------------------------------------------------
1 | Sarah Connor | Planet Earth | Nice woman | sarah_connor
2 | Sarah Connor | USA, NY | Mean woman | sarah_c
3 | John Connor | USA, NY | n00b | john123
In the situations when there are two or more records in user_alias table for the same person (equal id's), you will get something like this:
id | name | address | comments | user
-------------------------------------------------------------
4 | Bill Clinton | White House | President | bill
4 | Bill Clinton | White House | President | monica

Related

Rows which do not exist in a table

I have a lists of names John, Rupert, Cassandra, Amy, and I want to get names which are not exists in table: Cassandra, Amy
How should I write such query?
My table:
+----+--------+-----------+------+
| id | name | address | tele |
+----+--------+-----------+------+
| 1 | Rupert | Somewhere | 022 |
| 2 | John | Doe | 029 |
| 3 | Donald | Armstrong | 021 |
| 4 | Bob | Gates | 022 |
+----+--------+-----------+------+
Think in sets. You add names to a the result set with UNION ALL, you remove names from the result set with EXCEPT.
select 'John'
union all
select 'Rupert'
union all
select 'Cassandra'
union all
select 'Amy'
except
select name from mytable;
Build up a list of your names to check and do a left join to the users table:
with to_check (name) as (
values
('John'), ('Rupert'), ('Cassandra'), ('Amy')
)
select tc.name as missing_name
from to_check tc
left join the_table tt on tt.name = tc.name
where tt.name is null;
SQLFiddle example: http://sqlfiddle.com/#!15/5c4f5/1
Hope your list is in form of table lets its be table b and your original table as a
now SQL query goes like it
Select name from a where name not in (select name from b);
Think this will give you solution as per my understanding. Also if further details are required please comment.
Also its more important to search for an answer as it look like its a question from a book/Class. Please try out to find solution could have got much more information like link below
How to write "not in ()" sql query using join

SQL duration between dates for different persons

hopefully someone can help me with the following task:
I hVE got 2 tables Treatment and 'Person'. Treatment contains the dates when treatments for the different persons were started, Person contains personal information, e.g. lastname.
Now I have to find all persons where the duration between the first and last treatment is over 20 years.
The Tables look something like this:
Person
| PK_Person | First name | Name |
_________________________________
| 1 | A_Test | Karl |
| 2 | B_Test | Marie |
| 3 | C_Test | Steve |
| 4 | D_Test | Jack |
Treatment
| PK_Treatment | Description | Starting time | PK_Person |
_________________________________________________________
| 1 | A | 01.01.1989 | 1
| 2 | B | 02.11.2001 | 1
| 3 | A | 05.01.2004 | 1
| 4 | C | 01.09.2013 | 1
| 5 | B | 01.01.1999 | 2
So in this example, the output should be person Karl, A_Test.
Hopefully its understandable what the problem is and someone can help me.
Edit: There seems to be a problem with the formatting, the tables are not displayed correctly, I hope its readable.
SELECT *
FROM person p
INNER JOIN Treatment t on t.PK_Person = p.PK_Person
WHERE DATEDIFF(year,[TREATMENT_DATE_1], [TREATMENT_DATE_2]) > 20
This should do it, it is however untested so will need tweaking to your schema
Your data looks a bit suspicious, because the first name doesn't look like a first name.
But, what you want to do is aggregate the Treatment table for each person and get the minimum and maximum starting times. When the difference is greater than 20 years, then keep the person, and join back to the person table to get the names.
select p.FirstName, p.LastName
from Person p join
(select pk_person, MIN(StartingTime) as minst, MAX(StartingTime) as maxst
from Treatment t
group by pk_person
having MAX(StartingTime) - MIN(StartingTime) > 20*365.25
) t
on p.pk_person = t.pk_person;
Note that date arithmetic does vary between databases. In most databases, taking the difference of two dates counts the number of days between them, so this is a pretty general approach (although not guaranteed to work on all databases).
I've taken a slightly different approach and worked with SQL Fiddle to verify that the below statements work.
As mentioned previously, the data does seem a bit suspicious; nonetheless per your requirements, you would be able to do the following:
select P.PK_Person, p.FirstName, p.Name
from person P
inner join treatment T on T.pk_person = P.pk_person
where DATEDIFF((select x.startingtime from treatment x where x.pk_person = p.pk_person order by startingtime desc limit 1), T.StartingTime) > 7305
First, we need to inner join treatements which will ignore any persons who are not in the treatment table. The where portion now just needs to select based on your criteria (in this case a difference of dates). Doing a subquery will generate the last date a person has been treated, compare that to each of your records, and filter by number of days (7305 = 20 years * 365.25).
Here is the working SQL Fiddle sample.

SQLite, selecting values having same criteria (throughout all table)

I have an sqlite database table similar to the one given below
Name | Surname | AddrType | Age | Phone
John | Kruger | Home | 23 | 12345
Sarah | Kats | Home | 33 | 12345
Bill | Kruger | Work | 15 | 12345
Lars | Kats | Home | 54 | 12345
Javier | Roux | Work | 45 | 12345
Ryne | Hutt | Home | 36 | 12345
I would like to select Name values matching same "Surname" value for each of the rows in the table.
For example, for the first line the query would be "select Name from myTable where Surname='Kruger'" whereas for the second line the query would be "select Name from myTable where Surname='Kats' and so an....
Is it possible to traverse through the whole table and select all values like that?
PS : I will use these method in a C++ application, the alternative method is to use sqlite3_exec() and process each row one by one. I just want to know if there is any other possible way for the same approach.
I'd do:
sqlite> SELECT group_concat(Name, '|') Names FROM People GROUP BY Surname;
Names
----------
Ryne
Sarah|Lars
John|Bill
Javier
Then split each value of "Names" in C++ using the "|" separator (or any other you choose in group_concat function.
Basically you just want to exclude any records that don't have a buddy.
Something simple like joining the table against itself should work:
SELECT a.Name
FROM tab AS a
JOIN tab AS b
ON a.Surname = b.Surname;
Just returning the full sorted table and doing the duplicate check yourself may be faster if incidence is high (and will always be high for all sets of data). That would be a pretty strong assumption though.
SELECT Name
FROM tab
SORT BY Surname;

SELECT a subset of records from Table A that match two columns in table B

I have a list of users in a database table called Users (SQL Server 2008 R2). In addition to the user's UserName, there are two fields that classify the user - for simplicity we'll say Department and JobTitle.
| UserName | Department | JobTitle |
------------------------------------------
| Joe | IT | SysAdmin |
| Jim | IT | DBA |
| Jeff | Sales | SalesMgr |
| Mack | Sales | Rep |
I also have a table, ActiveJobs, that lists certain combinations of Department and JobTitle that I actually care about.
| Department | JobTitle |
-----------------------------
| IT | SysAdmin |
| Sales | SalesMgr |
| Sales | Rep |
I want to select each of the records from Users that matches the combination of Department / JobTitle in ActiveJobs. I thought this query would do it:
SELECT Users.*
FROM Users
INNER JOIN ActiveJobs DEP
ON Users.Department = DEP.Department
INNER JOIN ActiveJobs JOB
ON Users.JobTitle = JOB.JobTitle
But that returns the same User record more than once in many cases (which I think is caused by the duplicates in the Department column - but I don't really understand why). For the example above, I'm getting (Joe, Joe, Jim, Mack) even though I was hoping to just get (Joe, Jim, Mack).
What query would get the subset of User records that has a matching combination of Department and JobTitle in Active Jobs?
Put an "AND" in your join clause instead of joining twice.
SELECT Users.*
FROM Users
INNER JOIN ActiveJobs DEP
ON Users.Department = DEP.Department AND Users.JobTitle = DEP.JobTitle
Seems like one join on two attributes would work, rather than two joins on one attribute each. Can you JOIN ON ... AND ... ? (Away from computer)

SELECT certain fields based on certain WHERE conditions

I am writing an advanced MySQL query that searches a database and retrieves user information. What I am wondering is can I select certain fields if WHERE condition 1 is met and select other fields if WHERE condition 2 is met?
Database: users
------------------------
| user_id | first_name |
------------------------
| 1 | John |
------------------------
| 2 | Chris |
------------------------
| 3 | Sam |
------------------------
| 4 | Megan |
------------------------
Database: friendship
--------------------------------------
| user_id_one | user_id_two | status |
--------------------------------------
| 2 | 4 | 0 |
--------------------------------------
| 4 | 1 | 1 |
--------------------------------------
Status 0 = Unconfirmed
Status 1 = Confirmed
OK, as you can see John & Megan are confirmed friends while Chris & Megan are friends but the relationship is unconfirmed.
The query I am trying to write is as follow: Megan(4) searches for new friends I want all of the users except for the ones she is a confirmed friend with to be returned. So, the results should return 2,3. But since a relationship with user_id 2 exists but is not confirmed, I want to also return the status since an entry in the friendship table does exist between the two. If a user exist but there is no connection in the relationship table it still returns that users information but returns status as a NULL or doesn't return status at all since it doesn't exist in that table.
I hope this makes since. Ask questions if you need to.
Why not use a left join or an if-not-exists?
SELECT users.*
FROM (users LEFT JOIN friendships
ON status=1 AND (user_id_one=user_id OR user_id_two=user_id) )
WHERE
status IS NULL
or
SELECT users.*
FROM users
WHERE
NOT EXISTS (SELECT *
FROM friendships
WHERE status=1
AND (user_id_one=user_id
OR user_id_two=user_id))
You can create to separate queries and then UNION the result tables. In each query, add a field that always has the same value.
So something like this should work:
(SELECT id, 'Not Friends' As Status FROM t1 WHERE condition1)
UNION
(SELECT id, 'Unconfirmed' As Status FROM t1 WHERE condition2)
Just make sure the same number and name of fields exists in both queries.