MySql crosstab 3 tables, T1=rows, T2=columns, T3=values - mysql

I have a need to display user-levels for all possible users(T1) in all possible Pages(T2) whereby the values are stored in another table (T3) like:
UserID, Page, Level(R,E,W,A,O)
(Read,Edit,Write,Assistant,Owner)
But I just can't understand how to dynamically get the columns made and then refer to it as LAST(col1)
Any hint in the right direction will be appreciated.
I know how to get it done in a number of foreach loops in php but I believe it should be possible in MySql?..
Tables look like:
Table 1; Users
ID | Name
------------------
1 | James
------------------
2 | John
------------------
3 | Peter
------------------
Table 2; Pages
ID | PageName
------------------
1 | Home
------------------
2 | Members
------------------
3 | Courses
------------------
4 | Lybrary
------------------
5 | StrangePage
------------------
6 | Unused Page
------------------
Table 3; UserLevels
ID | User | Page | Lev
---------------------------------------
1 | James | Home | W
---------------------------------------
2 | James | Members | R
---------------------------------------
3 | James | Lybrary | O
---------------------------------------
4 | John | Home | R
---------------------------------------
5 | Peter | Home | O
---------------------------------------
6 | Peter | Courses | A
---------------------------------------
Expected out put would contain all users as rows, all pages as columns, all permissions (where available) as results:
User | Home | Members | Courses | Lybrary | StrangePage | Unused Page
-----------------------------------------------------------------------
James | W | R | | | |
-----------------------------------------------------------------------
John | R | | | | |
-----------------------------------------------------------------------
Peter | O | | A | | |
-----------------------------------------------------------------------

Related

Get average from nested eloquent relationship

I would like to calculate average from nested relationship between eloquent models. So, let's say, I have 3 tables called programs, activities and statistics.
For simplicity sake, I will try to minimize the structure as follows:
program table:
-------------
| id | name |
-------------
| 1 | Foo |
| 2 | Bar |
-------------
activities table:
-----------------------------------
| id | program_id | name |
-----------------------------------
| 1 | 1 | Foo 1 |
| 2 | 1 | Foo 2 |
| 3 | 1 | Foo 3 |
| 4 | 2 | Bar 1 |
| 5 | 2 | Bar 2 |
-----------------------------------
statistics table:
-----------------------------------
| id | activity_id | type | score |
-----------------------------------
| 1 | 1 | A | 25 |
| 2 | 1 | B | 20 |
| 3 | 1 | A | 22 |
| 4 | 2 | A | 27 |
| 5 | 2 | B | 24 |
| 6 | 3 | A | 23 |
-----------------------------------
Now, what I want to get is the average of score of a program with specific type of statistic. I defined relationship in models, and tried following code, but no avail:
$program = Program::find(1);
$avg = $program->activities->where('statistics.type', 'A')->avg('statistics.value');
$avg always 0 or null if there is no activities in program, even without where clause.
i'm sure that i defined the relationship correctly because $program->activities returns a sets of activities and $activity-> statistics return a sets of statistics as well.
Any ideas?
You can use whereHas() like this:
Statistics::whereHas('activity', function ($q) use($programId) {
$q->where('program_id', $programId);
})
->where('type', 'A')
->avg('score');
Make sure you've defined activity relationship which should be "statistics belongsTo() activity".

Normalisation of product/protocol review system

I'm working on a review system, where reviews for products are shown based on the outcome of a questionnaire.
Example:
What food do you like (Italian, French or fusion)
Which vegetables do you like (spinach, tomato or broccoli)
How much money would you like to spend on dinner ($0-$10, $11-$20 or $21-$30)
If someone selects Italian, tomato, $0-$10, then the user would see (for example) 20 types of pizza's, with reviews from other users shown.
But we only want to show products that have been reviewed for the exact same outcome of the questionnaire (we call this the protocol).
Table: questions
-----------------------------------
| id | question |
-----------------------------------
| 1 | What food do you like |
-----------------------------------
| 2 | Which vegetables do you... |
-----------------------------------
Table: possible_answers
-----------------------------------
| id | question_id | answer |
-----------------------------------
| 1 | 1 | Italian |
-----------------------------------
| 2 | 1 | French |
-----------------------------------
Table: products
---------------------
| id | product |
---------------------
| 1 | Pizza Salami |
---------------------
| 2 | Pizza cheese |
---------------------
From a database perspective (we're using mySQL), I'm wondering how to store the protocol attached to each review
[OPTION 1]
Table: reviews
---------------------------------------------------------------------------
| id | product_id | answer_q1_id | answer_q2_id | answer_q3_id | rating |
---------------------------------------------------------------------------
| 1 | 2 | 3 | 57 | 166 | 4 |
---------------------------------------------------------------------------
| 2 | 25 | 3 | 57 | 166 | 5 |
---------------------------------------------------------------------------
[/OPTION 1]
[OPTION 2]
Table: reviews
-------------------------------
| id | product_id | rating |
-------------------------------
| 1 | 2 | 4 |
-------------------------------
| 2 | 25 | 5 |
-------------------------------
Table: protocol
-----------------------------------------------
| id | review_id | question_id | answer_id |
-----------------------------------------------
| 1 | 1 | 1 | 3 |
-----------------------------------------------
| 2 | 1 | 2 | 57 |
-----------------------------------------------
| 2 | 1 | 3 | 166 |
-----------------------------------------------
[/OPTION 2]
Normally, I'd go with option 2 which just 'feels' better. But I'm not sure how one could query the protocol table to get all product reviews for a specific path in the questionnaire (protocol). For example when the user answers 'italian, spinach, 0-10', how do I find out which product reviews go with that combination of answers using option 2 (with option 1 it is obvious how to do this)?
I hope I've explained this well and I'm looking forward to reading thoughts from the community.
Greatly appreciated,
Lionel.

retrieving information from 3 tables

I have three tables:
users:
+----------+-----------------------------+-----------+
| users_id | user detail | otherID |
+----------+-----------------------------+-----------+
| 1 | user name or details | 1 |
| 2 | user name or details | 1 |
| 3 | user name or details | 4 |
| 4 | user name or details | 1 |
| 5 | user name or details | 21 |
| 6 | user name or details | 2 |
+----------+-----------------------------+-----------+
photos:
+----------+----------------+-----------+--------+---------+--------------+
| photosID | url | title | userID | likes | remarksID |
+----------+----------------+-----------+--------+---------+--------------+
| 1 | 7459.JPG | TITLE | 1 | 150 | 255 |
| 2 | 7510.JPG | TITLE | 1 | 146 | 247 |
| 3 | 7460.JPG | TITLE | 2 | 2 | 56 |
+----------+----------------+-----------+--------+---------+--------------+
remarks:
+-----------+---------------------------------------+---------+------------+
| remarksID | remark | userID | photoID |
+-----------+---------------------------------------+---------+------------+
| 1 | REMARKS for PhotoID 1 | 1 | 1 |
| 2 | REMARKS for PhotoID 1 | 1 | 1 |
| 3 | REMARKS for PhotoID 1 | 1 | 1 |
| 4 | REMARKS for PhotoID 2 | 1 | 2 |
| 5 | REMARKS for PhotoID 2 | 1 | 2 |
| 6 | REMARKS for PhotoID 3 | 2 | 3 |
+-----------+---------------------------------------+---------+------------+
I am trying to extract the remarks for a given users photo, but only want the photo to appear once but all the relevant remarks for the photo to be displayed for each users photo.
If there are no remarks then just display the photo without remarks.
The layout would look like this on a web page-
------------------------------------
Photograph 1
Remarks 1
Remarks 2
Remarks 1
------------------------------------
Photograph 2
NO remarks for photo
------------------------------------
Photograph 3
Remarks 1
Remarks 2
Remarks 3
Remarks 4
------------------------------------
Photograph 4
Remarks 1
Remarks 2
------------------------------------
Is my assumption correct that your difficulty is, how to get the database to do this? If so, then the answer is that this function (formatting the data), is not (or should not) generally be the responsibility of the database. Fetch the photos from the database as one result set, then fetch the matching comments in another, and let your application or reporting tool format the data the way you want it.

MySQL - Use Header Name as Part of Query Filter

I'm relatively new to MySQL and have come across a problem to which I cannot seem to find a solution. I have searched but could not find an answer. I'm open to the possibility that I'm not asking the question correctly. Here goes:
I'm trying to use the name of a given column and the values within that column from one table to pull values from another table. The first table contains 3 columns with the response codified. The second table contains the definitions for each code for each item. The same number code is associated with different meanings depending on the item. For example:
table1 (this table cannot change):
--------------------------------------------------------------
|result_id | f_initial | l_name | item_A | item_B | item_C |
--------------------------------------------------------------
| 1 | j | doe | 1 | 3 | 2 |
| 2 | k | smith | 3 | 1 | 2 |
| 3 | l | williams | 2 | 2 | 1 |
--------------------------------------------------------------
table2 (this table can be modified, split, or whatever needs to be done):
-------------------------------------------
|item_id | item_name | score | definition |
-------------------------------------------
| 1 | item_A | 1 | agree |
| 2 | item_A | 2 | neutral |
| 3 | item_A | 3 | disagree |
| 4 | item_B | 1 | likely |
| 5 | item_B | 2 | not likely |
| 6 | item_B | 3 | no reply |
| 7 | item_C | 1 | yes |
| 8 | item_C | 2 | no |
-------------------------------------------
My goal is for the query to output the following:
--------------------------------------------------------------------
|result_id | f_initial | l_name | item_A | item_B | item_C |
--------------------------------------------------------------------
| 1 | j | doe | agree | no reply | no |
| 2 | k | smith | disagree | likely | no |
| 3 | l | williams | neutral | not likely | yes |
--------------------------------------------------------------------
Any assistance or guidance is greatly appreciated. Thank you in advance.
You must join the two tables on the item_A/B/C and score columns
select t1.result_id, t1.f_initial, t1.l_name,
t2a.definition as item_a,
t2b.definition as item_b,
t2c.definition as item_c
from table1 t1
join table2 t2a on t2a.score = t1.item_a
join table2 t2b on t2b.score = t1.item_b
join table2 t2c on t2c.score = t1.item_c
where t2a.item_name = 'item_A'
and t2b.item_name = 'item_B'
and t2c.item_name = 'item_C'

MYSQL Stored Procedure to select different column data based on connected user's membership

I'm trying to create a stored procedure to return a list of IDs and a Computer name for each that varies based on the connected user's membership of a company, and that company's region, in the format:
ID | ComputerName
=================
....but I'm really not getting anywhere with it, and would be grateful of any help!
I need the value of ComputerName to be one of NameCompany, NameRegion, NamePublic depending on which Company/Region the logged in user is a Member of:
ComputerNamesTable:
ComputerID | CompnayID | NameCompany | NameRegion | NamePublic
================================================================
1 | 1 | AlicesPC | MarketingPC | GeneralPC
2 | 1 | BobsPC | FinancePC | SpecialPC
3 | 2 | AndysPC | AdminPC | ProtectedPC
4 | 3 | JanesPC | ReceptionPC | GeneralPC
User Table:
UserID | UserName | MemberofCompanyID
=====================================
1 | Jim | 1
2 | Sally | 2
3 | Ann | 3
Company Table:
CompanyID | CompanyName | MemberOfRegionID
==========================================
1 | Acme | North
2 | Sprockets | North
3 | Arkwrights | South
Ragion Table:
RegionID | RegionName
=====================
1 | North
2 | South
Such that:
Select (ID,ComputerName) from "StoredProcedure" for Jim returns:
ID | ComputerName
=================
1 | AlicesPC
2 | BobsPC
3 | AdminPC
4 | GeneralPC
Select (ID,ComputerName) from "StoredProcedure" for Sally returns:
ID | ComputerName
=================
1 | MarketingPC
2 | FinancePC
3 | AndysPC
4 | GeneralPC
Select (ID,ComputerName) from "StoredProcedure" for Ann returns:
ID | ComputerName
=================
1 | GeneralPC
2 | SpecialPC
3 | ProtectedPC
4 | JanesPC
I'm also trying to then add a "OverrideName" table that can amend things for a given user:
OverrideName Table:
OverrideID | UserID | ComputerID | OverrideName
======================================================
1 | 3 | 2 | Special-PC-TopFloor
So, Select (ID,ComputerName) from "StoredProcedure" for Ann:
ID | ComputerName
=================
1 | GeneralPC
2 | Special-PC-TopFloor
3 | ProtectedPC
4 | JanesPC
My thought process so far was to build up a result set of
ID, NamePublic
Then overwrite this using NameRegion, where the userid is in the company and the company is in the region.
Then overwrite that using NameCompany, where the userid is in the company.
And finally overwrite that with the data from the override table where entries match the username.
Any help or suggestions appreciated!
Thanks,
Ben