What we are trying to achieve is some level of cleansing on the table. This is what we currently have (this a subset of the table please)
+-----------+------------+-----------+------------+--------+-----------+------------+-------+
| STUDENTNO | LASTNAME | FIRSTNAME | PREFERNAME | GENDER | COURSE | YEAR | MAJOR |
+-----------+------------+-----------+------------+--------+-----------+------------+-------+
| auaw64 | Drury | Janet | Jane | f | DIPLOMA | 29/10/2011 | NO |
| auaw64 | Drury | Janet | Jane | f | BACHELORS | 29/09/2013 | YES |
| auqn70 | Givens | Jason | | m | DIPLOMA | 29/10/2011 | NO |
| auqn70 | Givens | Jason | | m | BACHELORS | 10/10/2012 | YES |
| mrpd90 | Blackstock | Williams | Bill | m | DIPLOMA | 29/10/2011 | NO |
| mrpd90 | Blackstock | Williams | Bill | m | BACHELORS | 29/09/2013 | YES |
| pyts84 | Peters | Theresa | | f | BACHELORS | 29/09/2013 | YES |
| qjgp97 | Aaron | Felina | | f | DIPLOMA | 29/10/2013 | NO |
| qzhs28 | Gyeong | Ma | | f | DIPLOMA | 29/10/2011 | NO |
| qzhs28 | Gyeong | Ma | | f | BACHELORS | 29/09/2013 | YES |
| uwnv95 | Anholt | Wilhemina | | f | MASTERS | 29/10/2011 | NO |
| uwnv95 | Anholt | Wilhemina | | f | BACHELORS | 10/10/2012 | YES |
| jaiw67 | Muguruza | David | Dave | m | MASTERS | 28/09/2014 | YES |
+-----------+------------+-----------+------------+--------+-----------+------------+-------+
But we need to reorder this table with the 'studentno' as the new primary key and then perform an update/upsert (which is where the new columns have now emerged)
+-----------+------------+-----------+------------+--------+--------------+------------+--------------+------------+
| STUDENTNO | LASTNAME | FIRSTNAME | PREFERNAME | GENDER | MAJOR_COURSE | MAJOR_YEAR | MINOR_COURSE | MINOR_YEAR |
+-----------+------------+-----------+------------+--------+--------------+------------+--------------+------------+
| auaw64 | Drury | Janet | Jane | f | BACHELORS | 29/09/2013 | DIPLOMA | 29/10/2011 |
| auqn70 | Givens | Jason | | m | BACHELORS | 10/10/2012 | DIPLOMA | 29/10/2011 |
| mrpd90 | Blackstock | Williams | Bill | m | BACHELORS | 29/09/2013 | DIPLOMA | 29/10/2011 |
| pyts84 | Peters | Theresa | | f | BACHELORS | 29/09/2013 | null | null |
| qjgp97 | Aaron | Felina | | f | DIPLOMA | 29/10/2013 | null | null |
| qzhs28 | Gyeong | Ma | | f | BACHELORS | 29/09/2013 | DIPLOMA | 29/10/2011 |
| uwnv95 | Anholt | Wilhemina | | f | BACHELORS | 29/09/2013 | DIPLOMA | 29/10/2011 |
| jaiw67 | Muguruza | David | Dave | m | MASTERS | 28/09/2014 | null | null |
+-----------+------------+-----------+------------+--------+--------------+------------+--------------+------------+
Essentially we want to take the first table and convert to the second but doing this using the functionalities inside PostgreSQL and also turning the 'studentno' into the unique key. We can then write the new table into another for another app to read or make use of but the new key will now offer a proper query handle unlike we have in the original table.
First create the course table
CREATE TABLE Courses (
id SERIAL,
course varchar);
Then insert all courses into the new table
insert into Courses(course)
select course from Participants GROUP BY course
Then create the n-n relation table
CREATE TABLE Participants_Courses (
id SERIAL,
studentno varchar,
course integer,
year date,
major boolean);
Then insert the values from Participants into the n-n table
INSERT INTO Participants_Courses AS PC (studentno, course, year,major)
VALUES (SELECT STUDENTNO, (SELECT id FROM Courses AS C where PC.course = C.course), YEAR, MAJOR);
Finally drop the unnecessary columns from the Participants table
ALTER TABLE Participants DROP COLUMN course;
ALTER TABLE Participants DROP COLUMN year;
ALTER TABLE Participants DROP COLUMN major;
This is normalized, I would not recommend to insert two courses into the same column of the table, because it would limit you. With this, a person could have many courses.
This is the Third normal form, see https://en.wikipedia.org/wiki/Third_normal_form
I did not test the SQL's so there may be syntax errors ;)
Disclaimer:
Doing this is completely backwards and wrong. It's doubling down on a bad table design by making it into a worse one. Do not use wide, denormalized tables as your primary data store.
Read:
https://en.wikipedia.org/wiki/Normalization
https://en.wikipedia.org/wiki/Third_normal_form
and get familiar with using joins.
If you use this solution then I am sorry to whoever has to maintain the code later. You appear to be determined to do it, and there are legitimate reasons you might want to make this transformation for things like a view or report, so here's how.
Use a self-left-join, treating studentno as the key. Something like:
select
l."STUDENTNO", l."LASTNAME", l."FIRSTNAME", l."PREFERNAME", l."GENDER",
l."COURSE" AS "MAJOR_COURSE", l."YEAR" AS "MAJOR_YEAR",
r."COURSE" AS "MINOR_COURSE", r."YEAR" AS "MINOR_YEAR"
FROM table1 l
LEFT OUTER JOIN table1 r
ON (l."STUDENTNO" = r."STUDENTNO"
AND (l."COURSE", l."YEAR") <> (r."COURSE", r."YEAR"))
WHERE (l."COURSE", l."YEAR") < (r."COURSE", r."YEAR")
OR r."COURSE" IS NULL;
A proper solution wouldn't rely on the lexical sort of BACHELORS before DIPLOMA and would instead use a CASE statement or a function to produce proper ordering, but since we're already piling wrong on top of wrong, it doesn't matter much.
SQLfiddle: http://sqlfiddle.com/#!15/2f49f/1
Now. Delete this, and go do it properly. Create a STUDENT table and COURSE table, and a STUDENT_COURSE table that joins them and records which students took which courses in which years. It's relational databases 101.
Related
Am new to Postgres SQL.
I have a big table that can be splitted to multiple table
ID_Student | Name_Student | Departement_Student | is_Student_works | job_title | Work_Departement | Location|
=============================================================================================================
1 | Rolf | Software Eng | Yes | intern SE | data Studio
| london |
2 | Silvya | Accounting | Yes | Accounter | TORnivo
| New York |
I want to split it into 3 tables ( student, departement, work) :
STUDENT TABLE
ID_Student | Name_Student | is_Student_works | Location|
========================================================
1 | Rolf | yes | london |
2 | Silvya | Yes | New York|
DEPARTEMENT TABLE
ID_DEPARTEMENT | Name_DEPARTEMENT |
===================================
1 | Software Eng |
2 | Accounting |
WORK TABLE
ID_WORK | Name_WORK |
===================================
1 | intern SE |
2 | Accounter |
I need Only the Query that Split the table into multiple tables, THE CREATION OF TABLES ARE NOT NEEDED.
I am trying to understand how to pivot data within T-SQL but can't seem to get it working. I have the following table structure
+-------------------+-----------------------+
| Name | Value |
+-------------------+-----------------------+
| TaskId | 12417 |
| TaskUid | XX00044497 |
| TaskDefId | 23 |
| TaskStatusId | 4 |
| Notes | |
| TaskActivityIndex | 0 |
| ModifiedBy | Orange |
| Modified | /Date(1554540200000)/ |
| CreatedBy | Apple |
| Created | /Date(2121212100000)/ |
| TaskPriorityId | 40 |
| OId | 2 |
+-------------------+-----------------------+
I want to pivot the name column to be columns expected output
+--------+------------------------+-----------+--------------+-------+-------------------+------------+-----------------------+-----------+-----------------------+----------------+-----+
| TASKID | TASKUID | TASKDEFID | TASKSTATUSID | NOTES | TASKACTIVITYINDEX | MODIFIEDBY | MODIFIED | CREATEDBY | CREATED | TASKPRIORITYID | OID |
+--------+------------------------+-----------+--------------+-------+-------------------+------------+-----------------------+-----------+-----------------------+----------------+-----+
| | | | | | | | | | | | |
| 12417 | XX00044497 | 23 | 4 | | 0 | Orange | /Date(1554540200000)/ | Apple | /Date(2121212100000)/ | 40 | 2 |
+--------+------------------------+-----------+--------------+-------+-------------------+------------+-----------------------+-----------+-----------------------+----------------+-----+
Is there an easy way of doing it? The columns are fixed (not dynamic).
Any help appreciated
Try this:
select * from yourtable
pivot
(
min(value)
for Name in ([TaskID],[TaskUID],[TaskDefID]......)
) as pivotable
You can also use case statements.
You must use the aggregate function in the pivot table.
If you want to learn more, here is the reference:
https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-2017
Output (I only tried three columns):
DB<>Fiddle
I have a table "Listing" that looks like this:
| listing_id | amenities |
|------------|--------------------------------------------------|
| 5629709 | {"Air conditioning",Heating, Essentials,Shampoo} |
| 4156372 | {"Wireless Internet",Kitchen,"Pets allowed"} |
And another table "Amenity" like this:
| amenity_id | amenities |
|------------|--------------------------------------------------|
| 1 | Air conditioning |
| 2 | Kitchen |
| 3 | Heating |
Is there a way to join the two tables in a new one "Listing_Amenity" like this:
| listing_id | amenities |
|------------|-----------|
| 5629709 | 1 |
| 5629709 | 3 |
| 4156372 | 2 |
You could use unnest:
CREATE TABLE Listing_Amenity
AS
SELECT l.listing_id, a.amenity_id
FROM Listing l
, unnest(l.ammenities) sub(elem)
JOIN Amenity a
ON a.ammenities = sub.elem;
db<>fiddle demo
I am a novice self-teaching Microsoft Access.
I have an MS Access database with a table of students (Table1).
Table1
+----+-----------+----------+------------+------------+
| id | firstname | lastname | Year_Group | Form_Group |
+----+-----------+----------+------------+------------+
| 2 | mnb | nbgfv | 7 | 1 |
| 3 | jhg | uhgf | 8 | 2 |
| 4 | poi | ijuy | 9 | 2 |
| 5 | tgf | tgfd | 10 | 2 |
| 6 | wer | qwes | 11 | 2 |
+----+-----------+----------+------------+------------+
Every day students days are recorded sort of like Table2.
Table2
+----------+----+-----------+----------+------------+--------+-----------+----------+
| Date | id | firstname | lastname | Year_Group | Effort | Behaviour | Homework |
+----------+----+-----------+----------+------------+--------+-----------+----------+
| 28/02/19 | 2 | mnb | nbgfv | 7 | Good | Good | Y |
| 28/02/19 | 3 | jhg | uhgf | 8 | OK | OK | Y |
| 28/02/19 | 4 | poi | ijuy | 9 | Bad | Bad | N |
| 01/03/19 | 5 | tgf | tgfd | 10 | Good | OK | Y |
| 01/03/19 | 6 | wer | qwes | 11 | Good | Good | Y |
+----------+----+-----------+----------+------------+--------+-----------+----------+
Is there a way (when using a list box or combo box) to select a student from Table1 so that their information is used for the corresponding columns in Table2?
Or is there a more efficient way to do this?
Firstly, you should normalise your data.
Currently, you are repeating the firstname, lastname, and Year_Group data in two separate tables, which not only bloats your database, but also means that such data must be maintained in two separate places, potentially leading to inconsistencies and then uncertainty as to which is the master.
Instead, I would suggest that your Students table should contain all information pertaining to the characteristics of a student:
Students
+----+-----------+----------+------------+------------+
| id | firstname | lastname | Year_Group | Form_Group |
+----+-----------+----------+------------+------------+
| 2 | mnb | nbgfv | 7 | 1 |
| 3 | jhg | uhgf | 8 | 2 |
| 4 | poi | ijuy | 9 | 2 |
| 5 | tgf | tgfd | 10 | 2 |
| 6 | wer | qwes | 11 | 2 |
+----+-----------+----------+------------+------------+
And the information pertaining to each school day should only reference the student ID in the Students table:
SchoolDays
+----------+----+--------+-----------+----------+
| Date | id | Effort | Behaviour | Homework |
+----------+----+--------+-----------+----------+
| 28/02/19 | 2 | Good | Good | Y |
| 28/02/19 | 3 | OK | OK | Y |
| 28/02/19 | 4 | Bad | Bad | N |
| 01/03/19 | 5 | Good | OK | Y |
| 01/03/19 | 6 | Good | Good | Y |
+----------+----+--------+-----------+----------+
Then, if you want to display the data in its entirety, you would use a query which joins the two tables, e.g.:
select
t2.date,
t1.firstname,
t1.lastname,
t1.year_group,
t2.effort,
t2.behaviour,
t2.homework
from
students t1 inner join schooldays t2 on t1.id = t2.id
I have three tables.
table a
| uid | name | number |
|-----+---------+--------|
| 1 | table | 1 |
| 2 | chair | 2 |
table b
| uid | name | number |
|-----+---------+--------|
| 1 | john | 1 |
| 2 | billy | 0 |
| 3 | bob | 2 |
| 4 | sally | 1 |
table c
| uid | table a | john | billy | bob | sally |
|-----+---------+--------+--------+-------|-------|
| 1 | table | T | | | T |
| 2 | chair | | | C | |
What I need to be able to do is look at the column names in table c, find the corresponding row entry in table b and if the numbers are the same as the numbers from table a, then set the table c value to T. Otherwise set it to C. This needs to be triggered whenever either table a or table b are updated.
How can I write an update the table using if or case statement.
Thanks.