Get data from 3 tables and show nice table - mysql

I have 3 tables: users, rooms, room_access.
in users is: user1, user2, user3
in rooms: room1 room2 roomN (i have about 10 rooms)
room_access (room,uid): room1, 1; room2,1; roomN,1; room2,3; room1,3;
So. User3 have access to room1, user2 have access to roome, etc.
In admin area i want to display that:
Basically table rooms content is displayed table header and table users content is displayed table rows. Maybe there is way that i can select all that data in single query? And where is check symbol, there i want to place checkboxes. So. I don't know how to made that table.

Essentially you are trying to return the data via a PIVOT. MySQL does not have a PIVOT function so you can use a combination of aggregate functions and a CASE statement. If you know ahead of time the number of rooms that you will have you can use:
select u.uname,
max(case when r.rname = 'room 1' then 'y' else 'n' end) room1,
max(case when r.rname = 'room 2' then 'y' else 'n' end) room2,
max(case when r.rname = 'room 3' then 'y' else 'n' end) room3
from users u
left join room_access ra
on u.uid = ra.userid
left join rooms r
on ra.roomid = r.rid
group by u.uname
see SQL Fiddle with Demo
But if you have an unknown number of rooms then you can use a prepared statement to create a dynamic version
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(CASE WHEN rname = ''',
rname,
''' THEN ''Y'' ELSE ''N'' END) AS ',
replace(rname, ' ', '')
)
) INTO #sql
FROM rooms;
SET #sql = CONCAT('SELECT u.uname, ', #sql, '
from users u
left join room_access ra
on u.uid = ra.userid
left join rooms r
on ra.roomid = r.rid
group by u.uname');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
see SQL Fiddle with Demo

Related

MySQL Multiple Query > storing rows into columns

I need to create a SQL query that lists the following tables. Lines from the language list as column names. Thanks
Picture table and query:
If languages are known upfront
SELECT r.id, r.parent,
MAX(CASE WHEN n.language_id = 1 THEN n.name END) cs,
MAX(CASE WHEN n.language_id = 2 THEN n.name END) en
FROM cat_route r LEFT JOIN cat_route_name n
ON r.id = n.cat_route_id
GROUP BY r.id
Here is SQLFiddle demo
If you want it to be dynamic depending on what languages you defined in language
SET #sql = NULL;
SELECT GROUP_CONCAT(CONCAT(
'MAX(CASE WHEN n.language_id = ', id, ' THEN n.name END) `', short, '`'))
INTO #sql
FROM language;
SET #sql = CONCAT(
'SELECT r.id, r.parent, ', #sql, '
FROM cat_route r LEFT JOIN cat_route_name n
ON r.id = n.cat_route_id
GROUP BY r.id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Here is SQLFiddle demo

SUM (some_column) WHERE some_column matches

So I have a table, and I'm trying to get the SUM(activity_weight) WHERE activity_typeid is unique.
Each competition has an unlimited amount of activity_typeid's.
As you can see in my code below, I wonder if there is some SQL function to find the SUM of something WHERE the id is unique for example?
THANKS FOR ANY HELP IN ADVANCE!
I've attached a photo of my table and desired output below
SELECT a.userid, u.name, u.profilePic ,
SUM(activity_weight) AS totalPoints ,
//sum the points when the activity_typeid is unique and make an extra column for each of those sums
SUM(CASE WHEN activity_typeid //is unique// THEN activity_weight ELSE NULL END) AS specific_points ,
FROM activity_entries a INNER JOIN users1 u ON u.id = a.userid
WHERE competitionId = '$competitionId' GROUP BY a.userid ORDER BY totalPoints
From the image it looks like you want a pivot, I believe in MySQL you achieve this by doing
SELECT a.userid, u.name, u.profilePic,
SUM(activity_weight) total_points,
SUM(CASE WHEN activity_typeid=22 THEN activity_weight ELSE 0 END) activity22,
SUM(CASE WHEN activity_typeid=33 THEN activity_weight ELSE 0 END) activity33,
SUM(CASE WHEN activity_typeid=55 THEN activity_weight ELSE 0 END) activity55
FROM activity_entries a
INNER JOIN users1 u ON u.id = a.userid
WHERE competitionId = '$competitionId'
GROUP BY a.userid
ORDER BY totalPoints
Edit for comments: there may be some syntax errors in the following but the idea is to create the sql dynamically and then execute it
-- generate sql for pivoted columns
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'SUM(CASE WHEN activity_typeid=',activity_typeid,
' THEN activity_weight ELSE 0 END) AS activity_', activity_typeid,
)
) INTO #sql
FROM activity_entries;
-- place above in full select query
-- n.b. the `$competitionId` could be a problem my MySQL is not v. good
SET #sql = CONCAT('SELECT a.userid, u.name, u.profilePic,
SUM(activity_weight) total_points,', #sql,
'FROM activity_entries
JOIN users1 u ON u.id = a.userid
WHERE competitionId = ''$competitionId''
GROUP BY a.userid, u.name, u.profilePic
ORDER BY totalPoints');
-- execute the dynamic sql
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SELECT SUM(something), ... FROM table t1 WHERE NOT EXISTS
(
SELECT id FROM table t2 WHERE t1.id <> t2.id AND t1.checkfield = t2.checkfield
)
GROUP BY ...
Basically, you want to select the sum of all records that have a value in checkfield where no record exists that has the same value for that field. Doing that is easy: just see if there is a record in the same table with the same value but a different id.
However, I'm not sure this is what you want. This only sums up unique records. If an activity id is not unique, it's not included at all, not even once.
You can try:
GROUP BY ...
HAVING SUM(activity_weight) AND COUNT(activity_typeid)=1
aggregate function for comparison only in the HAVING clause

Rows are represented as columns in a View

for my sense, I've a creative way of saving userdata. Let me explain:
I do not know which data is going to be saved in this database. For example, someone wants to save his icq number and i didn't know it before, where could he write it into? He dynamically creates a new field and in background there is an insert done in fields and an insert in user_fields where the new value of the new option is stored.
Table user:
id username
1 rauchmelder
Table fields:
id name
1 firstname
2 lastname
Table user_fields: (old values are stored as well as current, only youngest entry should be used)
id user_id fields_id value date
1 1 1 Chris 1.Mai
1 1 2 Rauch 1.Mai
1 1 1 Christopher 2.Mai
Result should be a View:
user.id user.username fields.firstname fields.lastname
1 rauchmelder Christopher Rauch
Firstly, does it make sense at all?
Secondly, should I solve it in MySQL or within the application?
Thridly, how to solve this in MySQL as a View?
In order to get the data into your columns, you can use an aggregate function with a CASE expression to convert the row data into columns.
If your fields are known ahead of time, then you can hard-code the values in your query:
select u.id,
u.username,
max(case when f.name = 'firstname' then uf.value end) firstname,
max(case when f.name = 'lastname' then uf.value end) lastname
from user u
left join
(
select uf1.*
from user_fields uf1
inner join
(
select max(date) maxDate, user_id, fields_id
from user_fields
group by user_id, fields_id
) uf2
on uf1.date = uf2.maxdate
and uf1.user_id = uf2.user_id
and uf1.fields_id = uf2.fields_id
) uf
on u.id = uf.user_id
left join fields f
on uf.fields_id = f.id
group by u.id, u.username;
See SQL Fiddle with Demo
But since you are going to have unknown fields, then you will need to use a prepared statement to generate dynamic SQL to execute. The syntax will be similar to this:
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'max(CASE WHEN f.name = ''',
name,
''' THEN uf.value END) AS `',
name, '`'
)
) INTO #sql
FROM fields;
SET #sql
= CONCAT('SELECT u.id,
u.username, ', #sql, '
from user u
left join
(
select uf1.*
from user_fields uf1
inner join
(
select max(date) maxDate, user_id, fields_id
from user_fields
group by user_id, fields_id
) uf2
on uf1.date = uf2.maxdate
and uf1.user_id = uf2.user_id
and uf1.fields_id = uf2.fields_id
) uf
on u.id = uf.user_id
left join fields f
on uf.fields_id = f.id
group by u.id, u.username');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
See SQL Fiddle with Demo

How to display one table values as table row and display values for this from another table

I'm trying to combine and display my 2 table are like bellow,
My first table structure is,
My second table is,
and my expected result is,
I tried like this but could't get result
select t2.field_value as t2.name
from content_fields t1
Join content_fields_type_richtext_data t2 ON t1.id = t2.field_id;
Is there any mistake in my table structure. How to get this result. Please help any one
MySQL does not have a PIVOT function but you can convert the row data into columns using an aggregate function with a CASE expression:
select t2.object_id,
max(case when t1.frontend_name = 'Bride Photo' then t2.field_value end) as `Bride Photo`,
max(case when t1.frontend_name = 'BrideGroom Photo' then t2.field_value end) as `BrideGroom Photo`,
max(case when t1.frontend_name = 'Bride Description' then t2.field_value end) as `Bride Description`,
max(case when t1.frontend_name = 'Groom Description' then t2.field_value end) as `Groom Description`,
max(case when t1.frontend_name = 'Wishes' then t2.field_value end) as `Wishes`
from content_fields t1
inner join content_fields_type_richtext_data t2
on t1.id = t2.field_id
group by t2.object_id;
If you have an unknown or dynamic number of values, then you will want to use a prepared statement to get the result:
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'max(CASE WHEN t1.frontend_name = ''',
frontend_name,
''' THEN t2.field_value END) AS `',
frontend_name, '`'
)
) INTO #sql
FROM content_fields;
SET #sql
= CONCAT('SELECT t2.object_id, ', #sql, '
from content_fields t1
inner join content_fields_type_richtext_data t2
on t1.id = t2.field_id
group by t2.object_id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

MySQL pivot table and JOINS

I have a mysql db with three tables
student
student_intervention
intervention details
I'm trying to do a pivot table view that shows all the students and has columns for each intervention type totalling up the different types of intervention for each student.
So far I have
SELECT t.`first_name`, t.`last_name`, t.`student_id`,
Count(IF(t.`intervention_details_id` = 1, 1, null)) AS Intervention1,
Count(IF(t.`intervention_details_id` = 0, 1, null)) AS Intervention2
FROM (
SELECT student.`student_id`, student.`first_name`,
student.`last_name`,
`student_intervention`.`intervention_details_id`
FROM student, student_intervention
WHERE student_intervention.student_id = student.`student_id`
) t
GROUP BY t.student_id
This works but it only shows data for students who have an intervention. I want a full list of students including those without an intervention. I think I need a JOIN but cannot figure out the right one.
Can anyone help?
use LEFT JOIN instead
SELECT a.`student_id`,
a.`first_name`,
a.`last_name`,
SUM(IF(COALESCE(b.`intervention_details_id`,0) = 1, 1, 0)) Intervention1,
SUM(IF(COALESCE(b.`intervention_details_id`,0) = 0, 1, 0)) Intervention2
FROM student a
LEFT JOIN student_intervention b
ON b.student_id = a.`student_id`
GROUP BY a.`student_id`, a.`first_name`, a.`last_name`
if you want prepared statement
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'SUM(CASE WHEN COALESCE(b.intervention_details_id ,0) = ',
COALESCE(b.intervention_details_id ,0),
' THEN 1 ELSE 0 END) AS ',
COALESCE(b.intervention_details_id ,0)
)
) INTO #sql
FROM student a
LEFT JOIN student_intervention b
ON b.student_id = a.student_id;
SET #sql = CONCAT('SELECT a.student_id , a.first_name , a.last_name , ', #sql, '
FROM student a
LEFT JOIN student_intervention b
ON b.student_id = a.student_id
GROUP BY a.student_id , a.first_name , a.last_name');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;