SQL query for the following Schema - mysql

DB Schema
students table
╔════════════╦═════════════╦══════════════╦═════════════╗
║ student_id ║ first_name ║ last_name ║ advisor_id ║
╠════════════╬═════════════╬══════════════╬═════════════╣
║ 1 ║ Tanisha ║ Blake ║ 2 ║
║ 2 ║ Jess ║ Goldsmith ║ NULL ║
║ 3 ║ Tracy ║ Wu ║ 3 ║
║ 4 ║ Alvin ║ Grand ║ 1 ║
║ 5 ║ Felix ║ Zimmermann ║ 2 ║
╚════════════╩═════════════╩══════════════╩═════════════╝
Advisors table
╔════════════╦════════════╦═══════════╗
║ advisor_id ║ first_name ║ last_name ║
╠════════════╬════════════╬═══════════╣
║ 1 ║ James ║ Francis ║
║ 2 ║ Amy ║ Cheng ║
║ 3 ║ Lamar ║ Alexander ║
║ 4 ║ Anita ║ Woods ║
╚════════════╩════════════╩═══════════╝
Get all students First name,Last name and advisors First and Last name excluding advisors with no students assigned

They are not the same as the first will exclude students and the second won't.

Yes both question are same in case u use inner join as it will not consider recordsets from each table, which do not have corresponding results in other table. But in case you use outer joins then you may have to put condition of weeding out records with null value in other table.
Foe example consider this query
Select * from students s left outer join advisers a on ( s.avisor_id = a.adviser_id)
This query will not only print those students with adviser but will also give students without adviser . SO simply putting a check for check Adviser_id is null will weed out not required record sets

Related

Access 2007 - Price Code from a Price Table

I have two tables. members and codes
I'm trying to get members.price to be automatically filled each time a new record is inserted - based on the code in members.price_code. It should match the codes.code and insert the correct codes.price in to members.price
I also need to do this for any existing members that currently have their codes set correctly, but the price field is empty
My members table:
╔════╦══════════════╦═════════════╦═══════╗
║ id ║ name ║ price_code ║ price ║
╠════╬══════════════╬═════════════╣═══════║
║ 1 ║ John Doe ║ M ║ ? ║
║ 2 ║ Jane Doe ║ M ║ ? ║
║ 3 ║ Peter Doe ║ S ║ ? ║
║ 4 ║ Lisa Doe ║ M ║ ? ║
╚════╩══════════════╩═════════════╩═══════╝
My Codes table
╔══════╦═══════════════╦═══════╗
║ code ║ description ║ price ║
╠══════╬═══════════════╬═══════╣
║ M ║ Member ║ 100 ║
║ S ║ Student ║ 50 ║
╚══════╩═══════════════╩═══════╝

How to merge two sql tables where B is a subset of A and should override A?

Table A (nothing is unique)
╔══════╦══════╦═══════════╦═══════════════╗
║ p_id ║ l_id ║ p_name ║ p_description ║
╠══════╬══════╬═══════════╬═══════════════╣
║ 212 ║ 1 ║ Ball ║ Red ║
║ 212 ║ 2 ║ Balle ║ Rouge ║
║ 301 ║ 1 ║ Horn name ║ Blue ║
╚══════╩══════╩═══════════╩═══════════════╝
Table B (p_id is unique)
╔══════╗
║ p_id ║
╠══════╣
║ 101 ║
║ 201 ║
║ 210 ║
║ 212 ║
║ 234 ║
║ 250 ║
║ 301 ║
║ 320 ║
╚══════╝
W.r.t p_id, Table A is a subset of Table B (all p_id should exist in Table B) but Table A contains different data. Both tables contain a lot more columns that I'm not showing. For table A I'm only concerned with the p_id. For table B I want to eliminate duplicates based on l_id. There will always be an entry with l_id of 1 but there may or may not be others which should be discarded (ie. a simple WHERE l_id=1 should do).
The result should be a table that has every p_id of Table B (once) with every column of Table A. Most of the rows will have no data in those other columns, because they didn't exist in Table B. So I should have this, for example:
╔══════╦══════╦═══════════╦═══════════════╗
║ p_id ║ l_id ║ p_name ║ p_description ║
╠══════╬══════╬═══════════╬═══════════════╣
║ 101 ║ ║ ║ ║
║ 201 ║ ║ ║ ║
║ 210 ║ ║ ║ ║
║ 212 ║ 1 ║ Ball ║ Red ║
║ 234 ║ ║ ║ ║
║ 250 ║ ║ ║ ║
║ 301 ║ 1 ║ Horn name ║ Blue ║
║ 320 ║ ║ ║ ║
╚══════╩══════╩═══════════╩═══════════════╝
From your description, this sounds like a left join:
select b.p_id, a.l_id, a.p_name, a.p_description
from b left join
a
on b.p_id = a.p_id and a.l_id = 1;
To get all rows from one table and the rows matching some condition from another you can use a left join:
select b.p_id, a.l_id, a.p_name, a.p_description
from b
left join a on b.p_id = a.p_id and a.l_id = 1
This will get you everything from B with values for the columns in A matching the where condition. For those rows in B that doesn't have any matches you'll get null values.

how to create dynamic pivot tables in MySQL

I'm having trouble generating pivot tables in MySQL and wonder if anyone can give me any tips and some documentation so I can finally resolve this problem.
My problem is as follows:
I have 2 tables in my database. clients contains customer information such as name, ssn and some personal data. In the cli_location table are client locations: address, telephone number, mobile phone and so on.
Sometimes we need to do selects based on criteria such as location, to pick up customers in a particular city. We also make queries based on cpf to get information for a specific customer.
I often need to cross these two tables. I currently do a left join. The problem with the left join is that sometimes the client has more than one phone, which generates new lines for each one.
When researching how to improve this behavior I discovered pivot tables, however I am not able to understand them.
1st table (clients):
╔════╦══════╦═══════╦════════════╦═══════╦════════╗
║ id ║ name ║ ssn ║ dt_birth ║ store ║ value ║
╠════╬══════╬═══════╬════════════╬═══════╬════════╣
║ 1 ║ john ║ 12345 ║ 1991-11-04 ║ 318 ║ 34.33 ║
║ 2 ║ john ║ 12345 ║ 1991-11-04 ║ 318 ║ 654.44 ║
║ 3 ║ john ║ 12345 ║ 1991-11-04 ║ 212 ║ 238.00 ║
║ 4 ║ alex ║ 54321 ║ 1988-05-20 ║ 321 ║ 334.44 ║
╚════╩══════╩═══════╩════════════╩═══════╩════════╝
2st table(cli_location):
╔════╦══════╦═══════╦══════════╦════════╦═════════╦═══════╦══════════╗
║ id ║ name ║ ssn ║ address ║ city ║ state ║ zip ║ tel ║
╠════╬══════╬═══════╬══════════╬════════╬═════════╬═══════╬══════════╣
║ 1 ║ john ║ 12345 ║ street1 ║ city1 ║ state1 ║ 23443 ║ 23432122 ║
║ 2 ║ john ║ 12345 ║ street1 ║ city1 ║ state1 ║ 23443 ║ 98765434 ║
║ 3 ║ john ║ 12345 ║ street2 ║ city5 ║ state7 ║ 54323 ║ 65765567 ║
║ 4 ║ john ║ 12345 ║ street3 ║ city4 ║ state9 ║ 76543 ║ 44323455 ║
║ 5 ║ alex ║ 54321 ║ street34 ║ city30 ║ state33 ║ 43234 ║ 86643457 ║
╚════╩══════╩═══════╩══════════╩════════╩═════════╩═══════╩══════════╝
When crossing the tables using left join, with the field of reference being ssn, the result has many duplicate lines. I am not able to change the structure of the data in production.
I had thought about doing something like :
╔════╦══════╦═══════╦════════════╦═══════╦════════╦════════╦════════╦════════╦════════╦══════════╦════════╦═════════╦═══════╦══════════╦════════╦════════╦════════╦══════════╦════════╦════════╦════════╦══════════╦══════════╦══════════╦══════════╗
║ id ║ name ║ ssn ║ dt_birth ║ store ║ value ║ store1 ║ value1 ║ store2 ║ value2 ║ address ║ city ║ state ║ zip ║ address1 ║ city1 ║ state1 ║ zip1 ║ address2 ║ city2 ║ state2 ║ zip2 ║ tel ║ tel1 ║ tel2 ║ tel3 ║
╠════╬══════╬═══════╬════════════╬═══════╬════════╬════════╬════════╬════════╬════════╬══════════╬════════╬═════════╬═══════╬══════════╬════════╬════════╬════════╬══════════╬════════╬════════╬════════╬══════════╬══════════╬══════════╬══════════╣
║ 1 ║ john ║ 12345 ║ 1991-11-04 ║ 318 ║ 34.33 ║ 318 ║ 654.44 ║ 212 ║ 238.00 ║ street1 ║ city1 ║ state1 ║ 23443 ║ street2 ║ city5 ║ state7 ║ 54323 ║ street3 ║ city4 ║ state9 ║ 76543 ║ 23432122 ║ 98765434 ║ 65765567 ║ 44323455 ║
║ 4 ║ alex ║ 54321 ║ 1988-05-20 ║ 321 ║ 334.33 ║ (null) ║ (null) ║ (null) ║ (null) ║ street34 ║ city30 ║ state33 ║ 43234 ║ (null) ║ (null) ║ (null) ║ (null) ║ (null) ║ (null) ║ (null) ║ (null) ║ (null) ║ 86643457 ║ (null) ║ (null) ║
╚════╩══════╩═══════╩════════════╩═══════╩════════╩════════╩════════╩════════╩════════╩══════════╩════════╩═════════╩═══════╩══════════╩════════╩════════╩════════╩══════════╩════════╩════════╩════════╩══════════╩══════════╩══════════╩══════════╝
The idea is to generate columns dynamically as there are more lines with the same type of information, as in the above table. Even if there are 2 rows with the same store, the value of field value differs so columns must be added for each store-value pair. The same for the address and phone fields as in the table above.
If someone could point me to some documentation, show me any examples or anything that helps me learn how to do this kind of thing I would be very grateful!
Edit
Thinking about this further, I'm confident that SQL can not do exactly what you need. This answer explains why, and lists your choices:
write application code to build a query dynamically, or
run your existing left join query, and then write application code to manipulate the result into the desired format.
However, if you're comfortable combining multiple values into one column, group_concat might get you close:
select
ssn,
name,
group_concat(distinct tel separator ', ') phones,
group_concat(distinct address separator '; ') addresses
from
(select clients.ssn,
clients.name,
cli_location.tel,
concat(cli_location.address, ', ', city, ' ', zip) address
from clients
left join cli_location
on clients.ssn=cli_location.ssn) c
group by ssn
produces:
| SSN | NAME | PHONES | ADDRESSES |
|-------|------|----------------------------------------|------------------------------------------------------------------|
| 12345 | john | 23432122, 44323455, 65765567, 98765434 | street1, city1 23443; street3, city4 76543; street2, city5 54323 |
| 54321 | alex | 86643457 | street34, city30 43234 |
http://sqlfiddle.com/#!2/ca287/25
Original
If you want a list of customers in a particular city:
select clients.ssn, clients.name
from clients
inner join cli_location
using(ssn)
where city = 'city1'
group by ssn;
http://sqlfiddle.com/#!2/ca287/3
Your schema is making this more difficult than it should be though. Consider normalizing it so that client names are in only one table, and split one-to-many relationships (like client:phone) into separate tables.

How to merge multiple rows in MySQL?

I ran into some problems while structuring my database, and I will ask two questions.
First question: below table needs to be merged by the same IDs
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ 0 ║ John ║ ║ ║
║ 0 ║ ║ 11 ║ ║
║ 0 ║ ║ ║ 6 ║
║ 1 ║ Dave ║ ║ ║
║ 1 ║ ║ 12 ║ ║
║ 1 ║ ║ ║ 7 ║
╚═════╩═══════╩═════╩═══════╝
so it should look like this;
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ 0 ║ John ║ 11 ║ 6 ║
║ 0 ║ Dave ║ 12 ║ 7 ║
╚═════╩═══════╩═════╩═══════╝
NOTE: id* is not AUTO_INCREMENT
Second question: You probably think that the former database structure is poor. The good thing is, I haven't created the database yet and I have been looking for a solution to add data to an existing row without removing old information, but if there is no old information, it would create a new row. Thanks in advance.
Second question explained
Virgin table
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ ║ ║ ║ ║
╚═════╩═══════╩═════╩═══════╝
some SQL statement
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ 0 ║ John ║ ║ ║
╚═════╩═══════╩═════╩═══════╝
the same SQL statement with different parameters
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ 0 ║ John ║ ║ ║
║ 1 ║ Dave ║ ║ ║
╚═════╩═══════╩═════╩═══════╝
another SQL statement
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ 0 ║ John ║ ║ ║
║ 1 ║ Dave ║ 12 ║ ║
╚═════╩═══════╩═════╩═══════╝
another SQL statement
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ 0 ║ John ║ ║ 6 ║
║ 1 ║ Dave ║ 12 ║ ║
╚═════╩═══════╩═════╩═══════╝
... and so on.
You should be able to apply an aggregate function to all the columns and then GROUP BY id:
select id,
max(name) name,
max(age) age,
max(grade) grade
from yourtable
group by id
See SQL Fiddle with Demo
As far as the DB structure, the only issue that I see is that you are inserting multiple records for the same user. You should be using an UPDATE statement to use the values instead of inserting.
It sounds like you want to use the REPLACE function in MySQL (here is a tutorial).
So the query would be similar to this:
REPLACE
INTO yourtable (`id`, `name`, `age`, `grade`)
VALUES (0, 'john', 11, null);
See SQL Fiddle with Demo
You could group by id, and use any aggregate function to pick the non-null row. This example uses max, but min would work too:
select id
, max(name) as name
, max(age) as age
, max(grade) as grade
from YourTable
group by
id

getting records of one and only one type

I was sitting several hours for trying to solve on specific problem but I couldn't get it. Finally, I decided to post it here. Here are some records,
╔════════╦════════════╦═════════╦══════════════════╗
║ AUTOID ║ PERSONNAME ║ FLOWER ║ Other columns... ║
╠════════╬════════════╬═════════╬══════════════════╣
║ 1 ║ Alex ║ Rose ║ ║
║ 2 ║ Rene ║ Rose ║ ║
║ 3 ║ Rene ║ Jasmin ║ ║
║ 4 ║ Darwin ║ Rose ║ ║
║ 5 ║ Alex ║ Rose ║ ║
║ 6 ║ Darwin ║ Jasmin ║ ║
║ 7 ║ Alex ║ Rose ║ ║
║ 8 ║ Rene ║ Jasmin ║ ║
║ 9 ║ Hello ║ World ║ ║
║ 10 ║ Hello ║ World ║ ║
╚════════╩════════════╩═════════╩══════════════════╝
How can I get this result, the person who has only one type of flower on all his/her records.
╔════════════╦════════════╗
║ PERSONNAME ║ FLOWERNAME ║
╠════════════╬════════════╣
║ Alex ║ Rose ║
║ Hello ║ World ║
╚════════════╩════════════╝
the best one I tried was this query below, and still not working.
SELECT DISTINCT t1.PersonName, t1.Flower
FROM TableName t1
INNER JOIN
(
SELECT personname, COUNT(DISTINCT flower) totals
FROM tableName
GROUP BY personname, Flower
) t2 ON t1.personname = t2.personname and
t2.totals = 1
Any Idea?
you can use GROUP BY clause, HAVING clause and COUNT() on this problem, no need to join on a subquery
SELECT PersonName, MAX(Flower) flowerName
FROM TableName
GROUP BY PersonName
HAVING COUNT(DISTINCT Flower) = 1
SQLFiddle Demo
or, because there's always more than one way to skin a cat...
SELECT x.*
FROM tablename x
LEFT
JOIN tablename y
ON y.personname = x.personname
AND ((y.flower <> x.flower)
OR (y.flower = x.flower AND y.autoid < x.autoid))
WHERE y.autoid IS NULL;