Dynamic pivot table with prepared statement in postgreSql - mysql

i would like convert data from Table1 as you can see on first picture on data in Pivot_table. Below you can see script in Mysql that is for dynamic pivot table, but i would like to know similar or suitable solution for this in Postgresql, if it is possible?
Table1:
PK Name Subject Grade**
-------------------------------------
1 Bob Math A
2 Bob History B
3 Bob Language C
4 Bob Biology D
5 Sue History C
6 Sue Math A
7 Sue Music A
8 Sue Geography C
Pivot_table:
Subject Bob Sue
-------------------------
Math A A
History B C
Language C
Biology D
Music A
Geography C
Script in Mysql:
SET #sql = NULL;
SELECT GROUP_CONCAT(DISTINCT
CONCAT('MAX(CASE WHEN name = ''', name,
''' THEN grade END) `', name, '`'))
INTO #sql
FROM table1;
SET #sql = CONCAT('SELECT subject, ', #sql, '
FROM table1
GROUP BY subject');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Thank you very much

Related

Combine all rows with the same name into a single row with multiple columns for the value

I have a MariaDB table with data like so:
Name | Value
John | 20
Adrian | 22
Tommy | 19
John | 24
John | 18
Adrian | 23
It is to be returned like so:
Name |Value1 |Value2 |Value3
John |20 |24 |18
Adrian |22 |23
Tommy |19
We will not know how many value columns there could be. I would prefer the solution to be SQL only. Grateful for any form of help! :)
Use group_concat
SELECT
Name,
GROUP_CONCAT(Value) 'Values'
FROM table_name
GROUP BY Name
ORDER BY Name;
Which will print all the values found in the second column.Its not exactly the presentation you asked for but it does give you the information in nearly the same format with a simple query.
If you need to evaluate the data there are many standard functions that you could use including:
AVG(Value)
COUNT(Value)
MAX(Value)
MIN(Value)
AVG(Value)
The alternative is a procedure which will be more complicated.
Is very hard to do in sql, because GROUP BY requires aggegate functions which distort the desired results. You could try make the column names the values and add a flag with a dynamic pivot.
Fiddle
create table t
(
name varchar(10),
value int
);
insert into t values
( 'John', 20),
( 'Adrian ', 22),
( 'Tommy ', 19),
( 'John ', 24),
( 'John ', 18),
( 'Adrian ', 23);
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(name = ''',
name,
''', 1, NULL)) AS `',
value,'`'
)
) INTO #sql
FROM t;
SET #sql = CONCAT('SELECT
t.name,
', #sql, '
FROM t
GROUP BY name ORDER BY name');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
name 22 23 18 24 20 19
Adrian 1 1
John 1 1 1
Tommy 1

MySQL Pivot Prepare Statement AS Integer error

Probably a very basic error but here is my problem.
There are users who are giving likes to certain pages of a given document and my aim is to return a breakdown of pages liked per user
Here are (a simplified view of) the two following tables:
User table
id name
---------
1 Jim
2 John
Vote table
userid pageno voteup
1 1 1
1 2 1
2 1 1
2 2 1
2 3 1
My desired output would be the following:
id name Page 1 Page 2 Page 3
1 Jim 1 1 0
2 John 1 1 1
I've made my prepared statement as followed. My aim is to display 'Page 1', 'Page 2' and so on for the column names instead of the 'test' below but as my pageno field is an int i fail in formatting the column name. I have tried various things but with no luck.
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(v.pageno = ',
pageno,
', v.voteup, 0)) AS ',
'test'
)
) INTO #sql
FROM vote;
SET #sql = CONCAT('SELECT u.id, u.name, ', #sql, '
FROM user u
LEFT JOIN vote AS v
ON u.id = v.id
GROUP BY u.id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
I'm sure this is something very basic I am missing. Could you help?
Thanks in advance
Link to SQLFiddle
This will do the trick although is not dynamic, if you need a dynamic solution.....
select
n.id,
n.name,
CASE WHEN v.pageno=1 THEN sum(v.voteup) ELSE NULL END as "Page 1"
CASE WHEN v.pageno=2 THEN sum(v.voteup) ELSE NULL END as "Page 2"
from votetable as v
join usertable as n on n.id = v.userid

MySQL - Select Query with junction table to one row

i have the following tables:
**entries**
entry_id | date | engineer | project
**entries_allowanes_map**
entry_id | allowance_id
**allowances**
allowance_id | allowance_name
I want to create a SELECT query that will give the following result:
entry_id | date | engineer | project | allowance_name1 | allowance_name2 | allowance_name_n...
The queries I have tried return a row for each allowance an entry has registered with. I want just one row with all allowances attached to it.
Thanks in advance
I would propose doing this with group_concat(). It doesn't put the values in separate columns, but it does put everything for a given entry on one row:
select e.entry_id, e.date, e.engineer, e.project,
group_concat(a.allowance_name) as allowances
from entries e join
entries_allowances_map f
on e.entry_id = eam.entry_id
allowances a
on eam.allowance_id = a.allowance_id
group by e.entry_id;
Here is the query that I got:
It outputs your expected results in different columns:
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'(SELECT max(CASE WHEN AL.ALLOWANCE_ID = ''',
ALLOWANCE_ID,
''' THEN 1 END) AS `',
ALLOWANCE_ID, '` FROM entries_allowanes_map AL WHERE E.ENTRY_ID = AL.ENTRY_ID ) AS `',
ALLOWANCE_NAME, '`'
)
) INTO #sql
FROM allowances;
SET #sql
= CONCAT('SELECT E.ENTRY_ID, E.DATE, E.ENGINEER, E.PROJECT, ', #sql, '
FROM entries as e');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Here is the SqlFiddle
Try
SELECT * FROM entries as e
INNER JOIN entries_allowanes_map as a ON e.entry_id=e.entry_id
INNER JOIN allownces as al ON al.allownce_id=a.allowance_id

Pivot Table Using MySQL

I have two tables Triples and Tags
Triples Table has the following Columns
id PostID TagID Value
1 1 1 Murder
2 1 2 New Brunswick
3 2 1 Theft
4 2 3 Gun
Tags Table has the following Columns
id TagName
1 Incident
2 Location
3 Weapon
I am trying to write sql to create a Pivot Table with Dynamic Headers
Output should be like this
PostID Incident Location Weapon
1 Murder New Brunswick
2 Theft Gun
Any help in writing the SQL would be appreciated. I have seen examples online but could not figure out this one
In order to pivot the data in MySQL, you will need to use both an aggregate function and a CASE expression.
If you have a known number of columns, then you can hard-code the query:
select p.postid,
max(case when t.tagname = 'Incident' then p.value end) Incident,
max(case when t.tagname = 'Location' then p.value end) Location,
max(case when t.tagname = 'Weapon' then p.value end) Weapon
from triples p
left join tags t
on p.tagid = t.id
group by p.postid;
See SQL Fiddle with Demo
But if you have an unknown number of columns, then you will need to use a prepared statement to generate dynamic SQL:
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'max(CASE WHEN TagName = ''',
TagName,
''' THEN p.value END) AS `',
TagName, '`'
)
) INTO #sql
FROM tags;
SET #sql
= CONCAT('SELECT p.postid, ', #sql, '
from triples p
left join tags t
on p.tagid = t.id
group by p.postid');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
See SQL Fiddle with Demo.
Both will give the result:
| POSTID | INCIDENT | LOCATION | WEAPON |
----------------------------------------------
| 1 | Murder | New Brunswick | (null) |
| 2 | Theft | (null) | Gun |

How to retrieve data from a polymorphic MySQL table

I have three tables in MySQL: application, questions, and questions_answer.
application stores user_id; questions stores question_id and the type of questions (i.e Name, NRIC, Name of School); questions_answer stores the answers referencing to user_id and question_id.
From what I understand, this type of association is called polymorphic association. Now I am at lost of how to retrieve data from different question_id and make them as column header instead.
I hope that makes sense.
Edit:
To illustrate, here are the respective table:
application:
user_id name
-------------------------------
100 Leon Barnacles
101 Richard Kennard
102 Fareeza Salleh
questions:
question_id question_name
---------------------------------------------
20 NRIC
21 Have you ever applied to TFM?
22 What's your current GPA?
23 Name of school
questions_answer:
question_id user_id answer
------------------------------------------------
20 100 880808-06-8990
20 100 900990-14-0911
23 102 SMK Taman Pandamaran
What I hope to retrieve:
Name NRIC Name of school
------------------------------------------------------------
Leon Barnacles 880808-06-8990
Richard Kennard 900990-14-0911
Fareeza Salleh SMK Taman Pandamaran
What you need is a PIVOT type function, MYSQL doesn't support PIVOT like SQL Server or Oracle. You can use following script to achieve pivot using max and case on questions table data
select group_concat(concat('max(case when question_id = ''', question_id, ''' then
answer end) as `', question_name ,'`')) into #sql from tfm_questions;
set #sql =
concat('select full_name, ', #sql, ' from
(
select a.full_name, q.question_name, an.answer, q.question_id
from tfm_application a
inner join tfm_questions_answer an on a.user_id = an.user_id
inner join tfm_questions q on an.question_id = q.question_id
) x
group by full_name');
select #sql;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SQL DEMO