Xaver
Xaver

Reputation: 11662

MySQL single statement to merge two tables

I'm sure this has been ask/answered already but I don't know how this kind of action is called and my SQL knowledge is limited.

I'm searching for a single SQL statement to merge two tables:

Table USER:

ID   hash
=========
1    abc
2    def
3    ghi

and the USER_FIELD table:

ID  user_id key        value
=============================
1   1       firstname  John
2   1       lastname   Doe
3   2       firstname  Justin
4   2       lastname   Case

Now I would like to know how I get this view:

ID  hash  firstname   lastname
================================
1   abc   John        Doe

So if I add an addtional entry in the USER_FIELD table with a key "email" I get a new column in the last result

Is this even possible just in MySQL or do I have to go and alter the result in PHP?

Is this even a good DB design or should I drop this an go with a different (which one?)

Upvotes: 1

Views: 1207

Answers (5)

Károly Nagy
Károly Nagy

Reputation: 1754

Generally this isn't considered as a good practice for flat type tables (like user data). This structure is usually used for storing user specified custom fields or meta data where you can have none or hundreds of them for a single instance.

The reason for avoiding this is if you want to get N user property you have to do N-1 join in MySQL and probably dynamically generate the query in the application which is suboptimal. Just put all your standard data in one table and you can use this user_field table for custom fields which only retrieved upon request.

If you're stuck with this structure to be able to do the querying efficiently I would change the user_field table to not have auto_increment id and rather make the user_id and key the PRIMARY KEY for the table. This way all the fields for a user will end up next to each other in the table space (assuming you're using InnoDB) and the lookup will be a primary key lookup. One further step would be to change the key to be tinyint and use lookup IDs instead of actual characters (you can even use CONSTANTS in the code to make it cleaner).

Upvotes: 2

Tsimtsum
Tsimtsum

Reputation: 1021

Another simple way to fetch data using subquery.

SELECT hash, (select value from USER_FIELD where key = 'firstname' and user_id=6 ) as firstname, (select value from USER_FIELD where key = 'lastname' and user_id=6 ) as lastname FROM `USER` where ID = 6 

but it is not good way. You will have to compromise with performance, if database goes large. You should use another design pattern.

Upvotes: 0

DevZer0
DevZer0

Reputation: 13535

Couple of Joins would do the trick.

SELECT u.id, u.hash, uf_f.value AS firstname, uf_l.value AS lastname
FROM user AS u 
LEFT JOIN user_field AS uf_f ON uf_f.user_id = u.id AND uf_f.key = 'firstname'
LEFT JOIN user_field AS uf_l ON uf_l.user_id = u.id AND uf_l.key = 'lastname'

Upvotes: 1

Gordon Linoff
Gordon Linoff

Reputation: 1269803

You can do this with a join and a group by:

select u.*, firstname, lastname
from user u join
     (select uf.user_id,
             max(case when key = 'firstname' then value end) as firstname,
             max(case when key = 'lastname' then value end) as lastname
      from user_field uf
      group by user_id
     ) uf
     on uf.user_id = u.id;

You can also do this with a sequence of joins:

select u.*. firstname.value, lastname.value
from user u join
     user_field firstname
     on u.id = firstname.user_id and firstname.key = 'firstname' join
     user_field lastname
     on u.id = lastname.user_id and lastname.key = 'lastname';

Your result seems to limit this to just one user id. You might want a where clause with this filter.

Upvotes: 2

Kevin Sjöberg
Kevin Sjöberg

Reputation: 2254

You want to use a JOIN-statement and use the ID and user_id as the subjects.

Upvotes: 0

Related Questions