Complex pivoting in mysql - mysql

I have a table in MySQL that has data and I want to achieve some sort of pivoting from the table, which has become complicated for me. I have tried looking into this but nothing seems to work for me. This is the structure of my table :
roomid| day| 1 | 2 | 3 | 4 | 5 | 6 |
------+----+---+---+---+---+---+---+
1 | 1 |BIO| | | | | |
1 | 2 | |CHE| | | | |
1 | 3 | | | | | |ENG|
1 | 4 | | |KIS| | | |
1 | 5 | | | | | |PHY|
2 | 1 |BIO| | | | | |
2 | 2 | |CHE| | | | |
2 | 3 | | | | |ENG| |
2 | 4 | | |KIS| | | |
2 | 5 | | | | | |PHY|
This table is holding timetable data, the roomid is id for rooms and the day is days from monday to friday (1 to 5). The columns 1 to 6 are period ids.
I need to organize the data to achieve results that show period ids for each class, each day. something like this :
|roomid| 1 | 2 | 3 | 4 | 5 | 6 | 1 | 2 | 3 | 4 | 5 | 6 | 1 | 2 | 3 | 4 | 5 | 6 | 1 | 2 | 3 | 4 | 5 | 6 | 1 | 2 | 3 | 4 | 5 | 6 |
-------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1 |BIO| | | | | | |CHE| | | | | | | | | |ENG| | |KIS| | | | | | | | |PHY|
2 |BIO| | | | | | |CHE| | | | | | | | | |ENG| | |KIS| | | | | | | | |PHY|
Kindly notice that the period ids repeat themselves for different days.

You can use conditional aggreagtion:
select room_id,
max(case when day = 1 then slot_1 end) as day_1_slot_1,
max(case when day = 1 then slot_2 end) as day_1_slot_2,
. . .
max(case when day = 2 then slot_1 end) as day_2_slot_1,
max(case when day = 2 then slot_2 end) as day_2_slot_2,
. . .
from schedule s
group by room_id

While not claiming to be a definitive solution, a normalised design might be somewhat as follows. Frankly, it stretches credulity to suggest that the present design is somehow more appropriate than this.
+--------+-----+------+---------+
| roomid | day | slot | subject |
+--------+-----+------+---------+
| 1 | 1 | 1 | BIO |
| 2 | 1 | 2 | BIO |
| 1 | 2 | 2 | CHE |
| 2 | 2 | 2 | CHE |
| 1 | 4 | 3 | KIS |
| 2 | 4 | 3 | KIS |
| 2 | 3 | 5 | ENG |
| 1 | 3 | 6 | ENG |
| 1 | 5 | 6 | PHY |
| 2 | 5 | 6 | PHY |
+--------+-----+------+---------+

Related

Enumerate rows in mysql based on groups with dates in different columns

I have a question very similar to this one, but different (aka, I couldn't extend the answer to that one to fit my purposes. Due to the second WHERE condition, specifically).
I have a table which tracks the visit number for customers. There are two types of visits:
| ID | InStoreVisit | InStoreDate | OnlineVisit | OnlineDate |
|----|--------------|-------------|-------------|------------|
| 1 | 1 | 1/1/11 | | |
| 1 | 2 | 1/2/11 | | |
| 1 | | | 1 | 1/3/11 |
| 1 | 3 | 1/4/11 | | |
| 2 | | | 1 | 2/2/12 |
| 2 | 1 | 2/3/12 | | |
| 2 | | | 2 | 2/4/12 |
I need to create a new column which has a sort of 'global visit number' as such:
| ID | InStoreVisit | InStoreDate | OnlineVisit | OnlineDate | GobalVisit |
|----|--------------|-------------|-------------|------------|------------|
| 1 | 1 | 1/1/11 | | | 1 |
| 1 | 2 | 1/2/11 | | | 2 |
| 1 | | | 1 | 1/3/11 | 3 |
| 1 | 3 | 1/4/11 | | | 4 |
| 2 | | | 1 | 2/2/12 | 1 |
| 2 | 1 | 2/3/12 | | | 2 |
| 2 | | | 2 | 2/4/12 | 3 |
I'm getting mixed up on the WHERE condition with which I can do the self-join. Any advice greatly appreciated.

Creating a log having the date of purchase

I need to create a log having the purchase date of an item.
Items can be owned by only one buyer at time. So, for example, if item1 was purchased by buyer2 in 2009 and after by buyer1 in 2015, then between 2009 and 2015 was owned by buyer2.
Here is my table:
+--------+------------+-----------+----------+
| id_doc | date | id_item | id_buyer |
+--------+------------+-----------+----------+
| 11 | 2016-06-07 | 1 | 4 |
| 10 | 2016-06-06 | 1 | 4 |
| 1 | 2015-11-30 | 1 | 1 |
| 9 | 2009-01-01 | 1 | 2 |
| 4 | 2001-01-12 | 1 | 2 |
| 8 | 1996-06-06 | 1 | 2 |
| 3 | 1995-05-29 | 1 | 1 |
| 2 | 1998-05-23 | 2 | 2 |
| 7 | 2014-10-10 | 3 | 2 |
| 6 | 2003-12-12 | 3 | 3 |
| 5 | 1991-01-12 | 3 | 2 |
+--------+------------+-----------+----------+
Here is a kind of table/view I need:
+------------+------------+-----------+----------+--------+
| date_from | date_to | id_item | id_buyer | id_doc |
+------------+------------+-----------+----------+--------+
| 2016-06-07 | - | 1 | 4 | 11 |
| 2016-06-06 | 2016-06-07 | 1 | 4 | 10 |
| 2015-11-30 | 2016-06-06 | 1 | 1 | 1 |
| 2009-01-01 | 2015-11-30 | 1 | 2 | 9 |
| 2001-01-12 | 2009-01-01 | 1 | 2 | 4 |
| 1996-06-06 | 2001-01-12 | 1 | 2 | 8 |
| 1995-05-29 | 1996-06-06 | 1 | 1 | 3 |
| 1998-05-23 | - | 2 | 2 | 2 |
| 2014-10-10 | - | 3 | 2 | 7 |
| 2003-12-12 | 2014-10-10 | 3 | 3 | 6 |
| 1991-01-12 | 2003-12-12 | 3 | 2 | 5 |
+------------+------------+-----------+----------+--------+
I've tried a lot with GROUP BY, GROUP_CONCAT, trying to access next record date, etc ... but I can't found out how to solve the problem.
Thanks in advance.
I finally found out the solution only for past purchases.
SELECT
main.id_doc, main.id_item, main.date AS "date_from", bi.date AS "date_to", main.id_buyer
FROM
MyTable main, MyTable bi
WHERE
bi.id_doc =
(
SELECT sub.id_doc
FROM MyTable sub
WHERE sub.id_item = main.id_item AND sub.date > main.date ORDER BY sub.date ASC LIMIT 1
);

Selected Child Categories based on parent categories from another table

I have two tables
rules
With three step hierarchy
|id | name | parent |
|---|-------|--------|
| 1 | A | 0 |
| 2 | B | 0 |
| 3 | A(1) | 1 |
| 4 | A(2) | 1 |
| 5 | B(1) | 2 |
| 6 | A(1.1)| 3 |
| 7 | A(1.2)| 3 |
| 8 | A(2.1)| 4 |
| 9 | B(1.1)| 5 |
| 10| A(3) | 1 |
Subject
|id | date | rules | group |
|---|---------------------|-------|-------|
| 1 | 2016-05-20 18:24:20 | 2 | AQR48 |
| 2 | 2016-05-20 19:31:17 | 5 | AQR52 |
| 3 | 2016-05-21 18:11:37 | 6,7,4 | AQR48 |
I need to get second step rules based on group and ruleid(first step) of subject table data
When group = 'AQR48' and rules.parent=1 result should be
|id | name | parent |
|---|-------|--------|
| 3 | A(1) | 1 |
| 4 | A(2) | 1 |
I tried it like this but with out success.
select rules.id,rules.name,rules.parent from rules left join subject on find_in_set(rules.id,subject.rules) where rules.parent=1 AND subject.group='AQR48'
With this I get output as
|id | name | parent |
|---|-------|--------|
| 4 | A(2) | 1 |
Anyone could help me with this

Select once for duplicate record

This is my tables which I need get data from these tables. Each user can under many type of groups for example 2, 3, 4
1)groups
|gp_id|gp_name|gp_status|
-------------------------------------
| 1 | Admin | Active |
| 2 | R&D | Active |
| 3 | Sales | Active |
| 4 | IT | Active |
2)modules (FK of table parent_modules)
|mod_id| mod_name| pmod_id |
---------------------------------------------
| 1 | name1 | 1 |
| 2 | name2 | 1 |
| 3 | name3 | 2 |
| 4 | name4 | 3 |
| ... | name... | 3 |
mod_id = 5,6,7.. and so on
3)parent_modules
|pmod_id| mod_name |pmod_status|
-----------------------------------------
| 1 | Contact Us | Active |
| 2 | Account Settings | Active |
| 3 | System Settings | Active |
4)group_details
(FK of table groups) (FK of table modules)
|gpd_id | gp_id | mod_id | base_gpd_rule_view/edit/update/insert |
-----------------------------------------------------------------------
| 1 | 3 | 1 | on |
| 2 | 3 | 2 | on |
| 3 | 3 | 3 | |
| 4 | 3 | 4 |
| 5 | 3 | 5 | on |
| 6 | 3 | 6 |
| 7 | 3 | 7 |
| 8 | 4 | 6 |
| 9 | 4 | 7 | on |
| 10 | 4 | 8 | on |
I have to select once only of duplicate results from group_details and this is the result that I want.
| gp_id | mod_id |
----------------------------------------------
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
| 3 | 4 |
| 3 | 5 |
| 3 | 6 |
| 3 | 7 |
| 4 | 8 |
So far this is what I did in my query but it shows me duplicate record.
//get user groups store in database. example group in database:2, 3, 4
$GroupList = explode(", ", $UserDetail['u_group']);
foreach($GroupList as $a)
{
$getParentModuleSQL = base_executeSQL("SELECT * FROM parent_modules WHERE pmod_status<>'Disable'" );
$count1 = base_num_rows($getParentModuleSQL);
while($ParentModuledata_row = base_fetch_array($getParentModuleSQL))
if ($count1!= 0)
{
base_executeSQL("SELECT gp.gp_id AS ID FROM group_details AS gp, modules AS m WHERE m.pmod_id =". $ParentModuledata_row['pmod_id'] ." AND gp.gp_id=". $a ." AND gp.mod_id = m.mod_id" AND (base_gpd_rule_view='on' OR base_gpd_rule_add='on' OR base_gpd_rule_edit='on' OR base_gpd_rule_delete='on') GROUP BY gp.mod_id);
}
}
i still dont understand your problems. if you want all modules a gp_id has access to - select * from group_details where gp_id = XX. If you just want each module, select * from modules.

Join tables to display in progress and completed courses

I am making a university-like database and am wondering how to join my enrolment and coursesTaken tables in order to show all the courses taken and presently enrolled in by all the students. Here is part of the enrolment table:
+--------------+------------+-------------------+---------------+-------------+
| EnrollmentID | EnrolledOn | Student_StudentID | Class_ClassID | Status |
+--------------+------------+-------------------+---------------+-------------+
| 1 | 08-23-2013 | 1 | 1 | In Progress |
| 2 | 08-23-2013 | 1 | 2 | In Progress |
| 3 | 08-23-2013 | 1 | 3 | In Progress |
| 4 | 08-23-2013 | 1 | 4 | In Progress |
| 5 | 08-23-2013 | 1 | 5 | In Progress |
| 6 | 08-23-2013 | 1 | 6 | In Progress |
| 7 | 08-23-2013 | 1 | 22 | In Progress |
| 8 | 08-23-2013 | 1 | 23 | In Progress |
| 9 | 08-23-2013 | 1 | 36 | In Progress |
| 10 | 08-23-2013 | 1 | 37 | In Progress |
| 11 | 08-23-2013 | 2 | 7 | In Progress |
| 12 | 08-23-2013 | 2 | 8 | In Progress |
| 13 | 08-23-2013 | 2 | 9 | In Progress |
| 14 | 08-23-2013 | 2 | 10 | In Progress |
| 15 | 08-23-2013 | 2 | 11 | In Progress |
and here is part of the courses taken table:
+-------------------+-----------------+-----------+--------+-----------+
| Student_StudentID | Course_CourseID | Pass/Fail | Credit | Status |
+-------------------+-----------------+-----------+--------+-----------+
| 2 | 1 | 1 | 1 | Completed |
| 2 | 2 | 1 | 1 | Completed |
| 2 | 3 | 1 | 1 | Completed |
| 2 | 4 | 1 | 1 | Completed |
| 2 | 5 | 1 | 1 | Completed |
| 2 | 6 | 1 | 1 | Completed |
| 2 | 22 | 1 | 1 | Completed |
| 2 | 23 | 1 | 1 | Completed |
| 2 | 24 | 1 | 1 | Completed |
| 2 | 25 | 1 | 1 | Completed |
| 3 | 1 | 1 | 1 | Completed |
| 3 | 2 | 1 | 1 | Completed |
| 3 | 3 | 1 | 1 | Completed |
| 3 | 4 | 1 | 1 | Completed |
| 3 | 5 | 1 | 1 | Completed |
| 3 | 6 | 1 | 1 | Completed |
As you can see some students such as student 1 do not have any courses taken since they are a first year and are only enrolled in courses. I would like a table that could put all of the studentID's from both tables in one table or view and list whether the status of their class is In Progress or if they have already completed the course.
Any advice on how I could join these 2 tables?
You can make a group by of both tables by student, then use a union query to add all the students id in one result.
Use this query as a subquery and make a left outer join to both tables and get the information related to the students you want.