I have a table in mysql, let's call it foo and it has a limitied amount of columns.
| id | name | date |
--------------------------
| 1 | bar | 2012-05-08 |
| 2 | buba | 2012-05-09 |
My users can add records to the table foo_field (stuff like, code, description, time...).
| id | name |
--------------------
| 1 | code |
| 2 | description |
| 3 | time |
In the table foo_field_value the values for the user-defined fields are stored, like so:
| id | foo_id | foo_field_id | value |
------------------------------------------
| 1 | 1 | 1 | b |
| 2 | 1 | 2 | Lalalala |
| 3 | 1 | 3 | 12:00 |
| 1 | 2 | 1 | c |
| 2 | 2 | 2 | We are go |
| 3 | 2 | 3 | 14:00 |
Ideally, I'd want one query which would give me a result like
| id | name | date | code | description | time |
------------------------------------------------------
| 1 | bar | 2012-05-08 | b | Lalalala | 12:00 |
| 2 | buba | 2012-05-09 | c | We are go | 14:00 |
Is this even possible without doing an inner join on the foo_fields_value table for every foo_field (generating the query with PHP by doing another query first).
It's possible to do it in just one, and quite simple.
We are going to modify the foo_field table a bit, adding a column corresponding to the foo table's id column, which I assume is the primary key.
so now we have
* foo
|------|
| id |
| name |
| date |
|------|
* foo_field
|-------------|
| foo_id |
| code |
| description |
| time |
|-------------|
Which means we can add the extra fields with one simple query:
SELECT * FROM foo
LEFT JOIN foo_field ON foo.id = foo_field.foo_id
Which will give us a result set of
| id | name | date | foo_id | code | description | time |
|----+-------+------------+--------+--------+-------------+----------|
| 1 | asdw | 2012-05-16 | 1 | asdasd | asdasd | 15:03:41 |
| 2 | fdgfe | 2012-05-18 | 2 | asdas | asdas | 15:03:41 |
| 3 | asdw | 2012-05-16 | 3 | asdas | asdas | 15:03:52 |
| 4 | fdgfe | 2012-05-18 | 4 | asdasd | asdasd | 15:03:52 |
I am still not sure I surely understood your question. If you want to create truly dynamic values and datastructures, I suggest you save a serialized array into a TEXT field in your database, but I also suggest you to overlook your solution if this is the case; if you want your solution to be able to grow, you want to manage as strict structures as possible.
What you are looking for is a pivot query. And since you have dynamic fields that need to converted to columns, check this article here about making automatic pivot queries
http://www.artfulsoftware.com/infotree/queries.php#523
Related
I'm currently running into a problem where I am required to pivot many rows into a single row, defined by a specific key. I know the GROUP_CONCAT functionality and am using that currently, but I would like to avoid having to use explode in PHP after fetching my results. My table looks like this:
----------------------------------
| primary_id | key_value | value |
----------------------------------
| 1 | my_key_1 | val_1 |
| 1 | my_key_2 | val_2 |
| 1 | my_key_3 | val_3 |
| 2 | my_key_4 | val_4 |
| 2 | my_key_5 | val_5 |
----------------------------------
And I would like to build a MySQL-Query that presents this exactly like this for primary id 1 and primary id 2:
-----------------------------------------------
| primary_id | my_key_1 | my_key_2 | my_key_3 |
-----------------------------------------------
| 1 | val_1 | val_2 | val_3 |
-----------------------------------------------
------------------------------------
| primary_id | my_key_4 | my_key_5 |
------------------------------------
| 2 | val_4 | val_5 |
------------------------------------
So I can retrieve the output as an array in PHP, with the form:
$output[1][my_key_1] = val_1
$output[1][my_key_2] = val_2
...
The GROUP_CONCAT functionality works, but it would be much nicer to just have the value in the form I needd it only using SQL.
Would appreciate any pointers, best regards.
Use a Pivot
select max(case (when key_value=my_key_1 then val_1 end)),
max(case (when key_value=my_key_2 then val_2 end)),
from...
etc...
+------+---------+----------+
| id | uid | assessors|
+------+---------+----------+
| 1 | 1 | Volvo |
| 2 | 2 | kenitra |
| 3 | 3 | rabat |
| 4 | 3 | Fahad |
| 5 | 3 | John |
+------+---------+----------+
I want to fetch the data on the base of uid because i use a Inner join to fetch data from other table now i want to fetch and show all assesors on uid but i get this output
+---------+----------+
| uid | assessors|
| 1 | Volvo |
| 2 | kenitra |
| 3 | rabat |
Desired Output is:
+---------+----------+
| uid | assessors|
| 1 | Volvo |
| 2 | kenitra |
| 3 | rabat |
| 3 | Fahad |
| 3 | John |
my query is =
SELECT * FROM lego_activity_answers WHERE uid = $studentid;
$studentid comes from another table
If you want to get all data in the lego_activity table except for id, simply select the individual fields you want, instead of querying *
SELECT uid, assessors FROM lego_activity_answers WHERE uid = $studentid;
SELECT DISTINCT uid ,assessors FROM lego_activity_answers where uid=$studentid;
( this may not perform well at all in large tables )
I have users table and I store all users (administrators, authors and normal users) in this table. I want to order authors (who writer column posts in a newspaper) among themselves. So which way should I follow? I have no idea what to do about it. Although I tried some methods. I added an "order" column to users table and I don't know what do to next. Please give me some advice. My table structure:
+----+-----------------+------------------+-------+-----------+-------+
| id | username | password | order | is_author | level |
+----+-----------------+------------------+-------+-----------+-------+
| 1 | admin2 | pass | 0 | 0 | 3 |
| 2 | admin1 | pass | 0 | 0 | 3 |
| 3 | writer&admin | pass | 0 | 1 | 3 |
| 4 | normaluser | pass | 0 | 0 | 0 |
| 5 | writer | pass | 0 | 1 | 1 |
+----+-----------------+------------------+-------+-----------+-------+
Additional info:
Level 3 - Super Administrator
Level 2 - Editor (Only can add news and manage users)
Level 1 - Author
Level 0 - Normal users
Why do I need is_author colunm?
Because every editor or super administrator isn't writer. For those who both author and administrator I added a additional column, is_author.
Give me some advice.
For your approach, create 2 tables -
1) users
2) user_role
users table:
+----+-----------------+------------------+--------------+----------+
| id | username | password | role_id (FK) | priority |
+----+-----------------+------------------+--------------+----------+
| 1 | admin2 | pass | 1 | NULL |
| 2 | admin1 | pass | 1 | NULL |
| 3 | writer&admin | pass | 2 | 1 |
| 4 | normaluser | pass | 4 | NULL |
| 5 | writer | pass | 3 | 3 |
+----+-----------------+------------------+--------------+----------+
user_role table:
+----+---------------------------+--------+
| id | role | level |
+----+---------------------------+--------+
| 1 | admin | 1 |
| 2 | writer and admin | 2 |
| 3 | writer | 3 |
| 4 | user | 4 |
+----+---------------------------+--------+
What's the most effective way to go about querying the table to output the results as shown?
Table:
+-----+----------+-----+
| PN | date | QTY |
+-----+----------+-----+
| AB1 | 01/12/14 | 4 |
| AB2 | 01/12/14 | 2 |
| AB3 | 01/12/14 | 7 |
| AB1 | 01/22/14 | 8 |
| AB3 | 01/25/14 | 3 |
| AB5 | 01/25/14 | 9 |
+-----+----------+-----+
Results:
+-----+----------+----------+----------+
| | 01/12/14 | 01/22/14 | 01/25/14 |
+-----+----------+----------+----------+
| AB1 | 4 | 8 | 0 |
| AB2 | 2 | 0 | 3 |
| AB5 | 7 | 0 | 9 |
+-----+----------+----------+----------+
What you want to do is called pivoting the data. It can be achieved in MySQL with some CASE statements and aggregate functions.
E.G.
SELECT PN,
SUM(CASE WHEN date='20141201' THEN qty END) AS day1Qty,
SUM(CASE WHEN date='20141202' THEN qty END) AS day2Qty
FROM table
GROUP BY PN
Of course you'll likely want to do something to dynamically handle the dates that are being aggregated so it isn't just a static list (unless that is what you're after).
See these answers for more info:
Pivot Table Using MySQL
MySQL pivot table
Would like to get the following as a result from the table structure below (MYSQL + PHP)
array[0][name]1,[desc]red,[title]hero,[desc]strong,[desc2]smells,[img][0]red1,[img][1]red2,[img][2]red3,ext[0].jpg,[ext][1].gif,[ext][2].png,[count][0]253,[count][1]211,[count][2]21,[count][3]121,[dist][0]5,[dist][1]5,[dist][2]12,[dist][3]2,[score][0]2,[score][1]3,[score][2]1,[score][3]5,[score][4]4,[val][0]5,[val][1]1,[val][2]4,[val][3]3,[val][4]4
The problem I have with a simple SELECT, JOIN and GROUP_CONCAT is that the values duplicate after selecting all the images.
I've tried various other ways for example selecting the data by row combined with a foreach loop in PHP, but I end up with lots of duplicates, and it looks very messy.
I also though about splitting it into multiple selects instead of using one, but I really would like to know if it can be done with one select.
Could someone help me with an MYSQL select? Thanks
game
+-----+----------+
| pid | name |
+-----+----------+
| 1 | red |
| 2 | green |
| 3 | blue |
+-----+----------+
detail
+-----+------+--------+-------+--------+
| id | pid | title | desc | desc 2 |
+-----+------+--------+-------+--------+
| 1 | 1 | hero |strong | smells |
| 2 | 2 | prince |nice | tall |
| 3 | 3 | dragon |big | green |
+-----+------+--------+-------+--------+
image
+-----+-----+-----+----+
| id | pid | img |ext |
+-----+-----+-----+----+
| 1 | 1 | red1|.jpg|
| 2 | 1 | red2|.gif|
| 3 | 1 | red3|.png|
+-----+-----+-----+----+
devmap
+-----+-----+-------+------+
| id | pid | count | dist |
+-----+-----+-------+------+
| 1 | 1 | 253 | 5 |
| 2 | 1 | 211 | 5 |
| 3 | 1 | 21 | 12 |
| 4 | 1 | 121 | 2 |
+-----+-----+-------+------+
stats
+-----+-----+-------+------+
| id | pid | scrore| val |
+-----+-----+-------+------+
| 1 | 1 | 2 | 5 |
| 2 | 1 | 3 | 1 |
| 3 | 1 | 1 | 4 |
| 4 | 1 | 5 | 3 |
| 5 | 1 | 4 | 3 |
+-----+-----+-------+------+
When you do a JOIN that involves more than a 1:1 mapping between tables you're going to have duplicate data, and there's no way to get around that in the query.
You can break it out into multiple selects, or you can loop through the result set and pare out whatever duplicate information you don't want.