How to create separate columns for values in Database - mysql

I have an SQL query that displays information from different tables in a database. One of the fields is called PieceType and this contains values like PLT, CASE, CTN etc. Each company could have a different number of PieceTypes e.g. company 4 could have just PLT, but company 5 could have 10 different types. I want to display these types in separate columns like:
Plt | CASE | CTN
My SQL query:
SELECT c.Name,
jp.PieceType
FROM customer c
LEFT JOIN job_new jn ON ja.JobID = jn.ID
LEFT JOIN job_pieces jp ON ja.JobID = jp.ID
WHERE c.Company_ID = compid
GROUP BY c.ID
Right now the query just displays one value from PieceTypes even though the company might have multiple piece types. I tried GROUP_CONCAT(DISTINCT jp.PieceType) but that displays all the values in the same column. I need each piece to be in a separate column.
Sample Database can be found on sqlfiddle: http://www.sqlfiddle.com/#!9/c34306/3

What you could do is a select where you do a lookup of the property you want.
ie:
Select
name,
(select property from job_pieces where companyid = id and property = 'A') as A,
(select property from job_pieces where companyid = id and property = 'B') as B,
(select property from job_pieces where companyid = id and property = 'C') as C
from company

I think you are looking for PIVOT TABLE. Hope this works :
SET group_concat_max_len=4294967294;
SET #COLUMNS = NULL;
/* Build columns to pivot */
SELECT GROUP_CONCAT(
DISTINCT CONCAT(
'CASE WHEN jp.PieceType = "',
jp.PieceType ,
'" THEN 1 ELSE NULL END AS ',
jp.PieceType
)
) INTO #COLUMNS
FROM job_pieces jp;
/* Build full query */
SET #SQL = CONCAT(
'SELECT
c.Name,
',#COLUMNS,'
FROM customer c
LEFT JOIN job_new jn ON ja.JobID = jn.ID
LEFT JOIN job_pieces jp ON ja.JobID = jp.ID
WHERE c.Company_ID = compid
GROUP BY c.ID'
);
/* Prepare and execute the query*/
PREPARE stmt FROM #SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

Related

What is wrong in Mysql select query with mysql variable concatenated with string?

I have bellow query but has problem
set #lang = "en";
SELECT
COUNT(*) AS total_of_user,
COUNT(*) AS "total_of_user_#lang",
src.district AS district_name,
src.district AS "district_name_#lang"
FROM users LEFT JOIN (
SELECT
d.district_code,
d.name_en AS district,
p.name_en AS province_name,
p.`province_code`
FROM
provinces AS p LEFT JOIN districts AS d ON p.province_code = d.province_code
WHERE
p.province_code = '01'
) AS src ON src.district_code = users.district_code
WHERE
users.district_code IS NOT NULL AND
users.district_code <> '' AND
users.province_code = '01'
GROUP BY users.district_code
If I remove " from query the never run, but above query run and result came as district_name_#lang but I need the column name to be as district_name_en.
For any help thanks.
You would need to use dynamic SQL for this:
set #lang = 'en';
set #sql = '
SELECT COUNT(*) AS total_of_user,
COUNT(*) AS total_of_user_#lang,
src.district AS district_name,
src.district AS district_name_#lang
FROM users LEFT JOIN
(SELECT d.district_code, d.name_en AS district, p.name_en AS province_name, p.`province_code`
FROM provinces p LEFT JOIN
districts d
ON p.province_code = d.province_code
WHERE p.province_code = ''01''
) src
ON src.district_code = users.district_code
WHERE users.district_code IS NOT NULL AND
users.district_code <> '''' AND
users.province_code = ''01''
GROUP BY users.district_code';
set #sql = replace(#sql, '#en', #en);
prepare stmt from #sql;
execute stmt;
deallocate prepare stmt;
Note: you cannot use parameters for column names or table names in a dynamic query.

How to get all records from one table and irrespective of where clause

Below is my Query, when I am putting where clause, my recordset get reduced. I can understand why it reducing,
But I am looking for all records from teacher_profiles table (31 records) and then corresponding details if there is any else blank.
Can any one suggest ? Using mySQL
SELECT
CONCAT(a.teacherFirstName , ' ', COALESCE(a.teacherMiddleName, ''), ' ', a.teacherLastName ) as teacherName ,
COALESCE(GROUP_CONCAT(DISTINCT c.subjectLongName SEPARATOR ', ') , '') AS subjects ,
COALESCE(GROUP_CONCAT(DISTINCT f.classStd SEPARATOR ', ') , '') AS classes ,
FROM
teacher_profiles a **<--- this table has 31 records. I need all these 31** Record in recordset
LEFT JOIN subjectteacherallocation b ON a.teacherId = b.teacherId
LEFT JOIN subject_master c ON b.subjectId = c.subjectId
LEFT JOIN timetabledistribution d ON a.teacherId = d.teacherId
LEFT JOIN TimeTableClassSection e ON d.TimeTableClassSectionId = d.TimeTableClassSectionId
LEFT JOIN class_master f ON f.classId = e.classId
WHERE b.academicYear='2015' <--- condition reducing record
GROUP BY a.teacherId

SELECT * FROM TABLE, TABLE depending on another query - SQL

Here's what I'm trying to achieve :
Select a person's or firm's name depending on the contact type.
Tables :
CONTACTS : PEOPLE FIRMS
- id - contact_id - contact_id
- type (person/firm) - name - name
I would like this kind of magic :
SELECT type
FROM contacts
WHERE contacts.id = 42;
SELECT model.name
FROM contacts LEFT JOIN model ON model.contact_id = contacts.id
WHERE contacts_id = 42
AND model = CASE (WHEN type = "person" THEN "people"
WHEN type = "firm" THEN "Firms" END); (Not sure this one works)
All in one query. Thanks !
You could do like below, join two tables and then decide which column to use according to contacts.type.
SELECT
(CASE WHEN t1.type = 'person' THEN t2.name WHEN t1.type = 'firm' THEN t3.name) AS contact_name
FROM contacts t1
LEFT JOIN people t2 ON t1.id = t2.contact_id
LEFT JOIN firms t3 ON t1.id = t3.contact_id
Simply left join both tables; one of them will match id and type. Use COALESCE then to display the one name found.
select coalesce(p.name, f.name) as name
from contacts c
left join people p on p.contacts_id = c.id and c.type = 'person'
left join firms f on f.contacts_id = c.id and c.type = 'firm'
where c.id = 42;
You can use dynamic sql like this:
declare
#table_name nvarchar(20),
#query nvarchar(max)
SELECT
#table_name =
case type
when 'person' then 'people'
when 'firm' then 'firms'
end
FROM contacts
WHERE contacts.id = 42;
set #query = N'SELECT ' + #table_name + '.name ' +
'FROM contacts LEFT JOIN model ON ' + #table_name + '.contact_id = contacts.id
WHERE contacts_id = 42 '
exec sp_executesql #query
Here is an alternative way without a join:
select
case when c.type = 'person' then
(select name from people p where p.contacts_id = c.id)
else
(select name from firms f on f.contacts_id = c.id)
end as name
from contacts c
where c.id = 42;
You see, there are many ways to address the problem. Just pick the one you find most readable.

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

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;