How to display columns as rows in a SQL query? - sql

I'm trying to display exam results form simple database containing two tables tblStudents and tblExamResults.
tblstudents contains student ID and Full_Name columns
In tblexamResults columns are Student_id, Subject and Marks.
as in below Picture
1- Currently I am displaying Student results using this query
SELECT tblStudents.Full_Name, tblExamResults.Subject, tblExamResults.Marks
FROM tblExamResults INNER JOIN
tblStudents ON tblExamResults.Student_id = tblStudents.Student_ID
order by tblStudents.Full_Name
2 - And results looks like in the following picture:
3 - But what I want is to display each subject as row and get result of each subject below it
So that each student's result is displayed in the same row:
Student_Name sub1_result sub2_Result sub3_Result
Like in the following picture (Excel screenshot)
So:
How I can display data in that format?
Is that possible in SQL Server?

select fullname,[english] english, [history] history, [physics] physics
from
(
select fullname,subject,marks
from (yourquery)
) src
pivot
(
max(marks)
for subject in ([english], [history], [physics])
) piv;
or
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.subject)
FROM (yourquery) c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT fullname, ' + #cols + ' from
(
select fullname,subject,marks
from (your query)
) x
pivot
(
max(marks)
for subject in (' + #cols + ')
) p '
execute(#query)
fullname english history physics
a 85 70 60
i 60 100 89
s 90 90 99

Finally I've used next part of #Chanukya Answer with little Changes
in that Answer i was getting error at line 5 becouse of parentheses in FROM (yourquery) c
Declare #query nvarchar(max);
DECLARE #cols AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.subject)
FROM tblExamResults c ' parentheses Removed from (tblExamResults) c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
print(#cols)
set #query = '
SELECT *
FROM (
SELECT tblStudents.Full_Name, tblExamResults.Subject, tblExamResults.Marks
FROM tblExamResults INNER JOIN
tblStudents ON tblExamResults.Student_id = tblStudents.Student_ID
) as s
PIVOT
(
sum(marks) FOR subject IN ('+ #cols +')
)AS pvt'
;
execute(#query)

Related

Convert Columns values into Rows in SQL 2008

It would be great if you can help me to convert Column into Rows in SQL Table.
Let say, I have 3 columns called:
Employee_ID
Shift_Date
Shift_ID
Currently it come up like this:
Table Like this
I want to appear like that as the result -
Result Table
But I want value in it, can you guys please help. Thanks.
This is a query I wrote but still error:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(shift_date)
from dbo.tbl_Multi_Shift_Employee WHERE Shift_Date BETWEEN CONVERT(DATE, '01/02/2018 00:00:00',103) AND CONVERT(DATE, '28/02/2018 00:00:00',103)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Employee_ID, total, Department_ID, shift_id, ' + #cols + ' from
(
select count(*) over(partition by t.Employee_ID) total,
s.Department_ID,
t.Employee_ID,
t.shift_id
from dbo.tbl_Multi_Shift_Employee t
inner join dbo.tbl_department s
on t.Department_ID = s.Department_ID
) x
pivot
(
count(shift_id)
for shift_id in (' + #cols + ')
) p '
PRINT #query
execute(#query)
First you must to remove shift_id from primary select because is used as pivot.
Second, change shift_id with shift_date that is the correct column you are using as pivot columns.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(shift_date)
from dbo.tbl_Multi_Shift_Employee WHERE Shift_Date BETWEEN CONVERT(DATE, '01/02/2018 00:00:00',103) AND CONVERT(DATE, '28/02/2018 00:00:00',103)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Employee_ID, total, Department_ID, ' + #cols + ' from
(
select count(*) over(partition by t.Employee_ID) total,
s.Department_ID,
t.Employee_ID,
t.shift_id,
t.shift_date
from dbo.tbl_Multi_Shift_Employee t
inner join dbo.tbl_department s
on t.Department_ID = s.Department_ID
) x
pivot
(
count(shift_id)
for shift_date in (' + #cols + ')
) p '
PRINT #query
execute(#query)

SQL Server: case/if else -select and apply function only if present in table

I have the following dynamic query that creates a pivoted table for each account_id against the products using an UDF. I need to add spaces after the UDF is executed depending up the account_id being matched to the specific tables. This works perfectly fine, and returns the 2nd table in the image, I just want to add some condition where it checks for account id's present in other tables and then adds spaces to output from the UDF eg- the account id in the pivot matches the id present in test_rev then 2 spaces if the account_id in the pivot matches the id present in test_oncontract then 3 spaces so on
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.A_NAME)
FROM TEST_11 c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT account_id, ' + #cols + ' INTO TEST_DETAIL from
(
select account_id
, dbo.make_table(apple,ball,cat,dog) AS newvalue
,a_name
from test_sample
) x
pivot
(
MAX(newvalue)
for a_name in (' + #cols + ')
) p '
execute(#query)
Image below shows how make_table udf converts the 1st table into 2nd just picking up the initials from each column name from the 1st table
I was able to call my function and add the required spaces withing the select.
But the case statement just executes the first condition and I cant get the records from the other tables. How can I implement if conditions instead of the case statements to to get data depending on all four conditions. Below is the code I am currently using:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.a_name)
FROM CRS_PRODLINE c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT account_id, ' + #cols + ' INTO TEST_DETAIL from
(select account_id,
(case
when exists (select account_id from [dbo].[TEST_R6])
then
dbo.make_sam_indicator112(apple,ball,cat,dog) + space(1) + ''rr''
when exists (select account_id from tbl_noR6)
then
dbo.make_sam_indicator112(apple,ball,cat,dog) + space(2) + ''cc''
when exists (select account_id from tbl_acct)
then
dbo.make_sam_indicator112(apple,ball,cat,dog) + space(3) + ''pp''
when exists (select account_id from test_NA)
then
dbo.make_sam_indicator112(apple,ball,cat,dog) + space(4) + ''no''
end) as newvalue,
a_name
from CRS_PRODLINE
) x
pivot
(
MAX(newvalue)
for a_name in (' + #cols + ')
) p '
execute(#query)

SQL Server 2012 Pivot

I have pivot solution that works fine but SQL server won't let me save it since it contains queries. Here is my original table:
ApplicationID ApplicationName ContactType Email
1 App1 type1 myemail#gmail.com
1 App1 type2 someemail#yahoo.com
2 App2 type1 email#email.com
2 App2 type3 someemail#yahoo.com
3 App3 type2 me#yahoo.com
Desired table:
ApplicationID ApplicationName Type1 Type2 Type3
1 App1 myemail#gmail.com
1 App1 someemail#yahoo.com
2 App2 email#email.com
& so on.... but i want dynamic pivoting meaning if there is new contactType added later on it just gets added to the view. Here is the query that I have which I'm unable to save as view:
DECLARE #cols AS NVARCHAR(MAX),
#colsNull AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(contactType)
from ApplicationContact
group by contactType
order by contactType
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #colsNull = STUFF((SELECT ', coalesce(' + QUOTENAME(contactType)+', '''') as '+QUOTENAME(contactType)
from ApplicationContact
group by contactType
order by contactType
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT ApplicationID, ApplicationName, ' + #colsNull + '
from
(
select ApplicationID, ApplicationName, contactType, Email flag
from ApplicationContact
) x
pivot
(
max(flag)
for contactType in (' + #cols + ')
) p '
execute(#query)
My error is: Incorrect syntax near the keyword 'DECLARE'
Please help. Thanks
Generally, views are single select statements used to join and/or filter data from tables, TVFs, or stored procedures. As a result the user can't declare variables in a view.
I'd suggest placing this script into a SP where you can declare variables and then calling the SP in the view.
Hope that helps.
If you just want the pivoted result, you can use the below queries.
Declare columns for pivot
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + ContactType + ']', '[' + ContactType + ']')
FROM
(
SELECT DISTINCT ContactType
FROM ApplicationContact
) PV
ORDER BY ContactType
Now you need to apply ROW_NUMBER to display Type 1, Type 2 etc in different rows.
DECLARE #query NVARCHAR(MAX)
SET #query = '
SELECT ApplicationID , ApplicationName, ' + #cols + '
FROM
(
SELECT ROW_NUMBER() OVER(PARTITION BY ApplicationID ORDER BY (SELECT 0))RNO,
ApplicationID , ApplicationName, ContactType, Email
FROM ApplicationContact
) x
PIVOT
(
MIN(Email)
FOR ContactType IN (' + #cols + ')
) p
ORDER BY ApplicationID;'
EXEC SP_EXECUTESQL #query
Click here to view result
As suggested here, you can use dynamic SQL in a view with SELECT * FROM OPENQUERY(...), but it's not that great of a solution. I would recommend using a proc as an alternative to a view.
EDIT - Adding my comment above to my answer:
If your data doesn't have to be real-time, you could use a job to execute your query to populate a table that you can use in place of the view. It can probably be run quite often since it doesn't seem to be that heavy of a query.

while converting column to row not able to fetch value from another table automatically

select *
from (
select vtid, convert(date, dtime) as Date from Transaction_tbl where locid = 5
) as vt
pivot (
count(vtid)
for vtid in (select vtid from VType_tbl)
) as pvt
while executing this query am getting error
Incorrect syntax near the keyword 'select'." and Incorrect syntax near
')'.
actually I have one more table,name= Vtype_table , How Can I load all vtid from vtype table in this query? I want to get output depend upon vtid.
Any help greatly appreciated.
Your PIVOT syntax is correct except you are using a SELECT statement inside your PIVOT.
You cannot use a SELECT statement inside the PIVOT IN clause to select column headers. It is required that the columns for the IN clause be known prior to executing the query.
If you are looking to generate a dynamic list of vtid values, then you will need to use dynamic SQL to get the result and the syntax will be similar to the following:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(vtid)
from VType_tbl
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Date, ' + #cols + '
from
(
select vtid, convert(date, dtime) as Date
from Transaction_tbl
where locid = 5
) d
pivot
(
count(vtid)
for vtid in (' + #cols + ')
) p '
execute(#query);
Edit, if you want the type names to appear then you should be able to use the following:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(vt_name)
from VType_tbl
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Date, ' + #cols + '
from
(
select v.vt_name, convert(date, dtime) as Date
from Transaction_tbl t
inner join VType_tbl v
on t.vtid = v.vtid
where locid = 5
) d
pivot
(
count(vt_name)
for vt_name in (' + #cols + ')
) p '
execute(#query)
Note: I am guessing on the column name for VType_tbl

PIVOT for in many column headers using field [duplicate]

This question already has answers here:
Get ROWS as COLUMNS (SQL Server dynamic PIVOT query)
(2 answers)
Closed 9 years ago.
I have the following basic SQL statement which uses the PIVOT command.
SELECT *
FROM
(
--select statement that creates my dataset
) s
PIVOT (Max(incidentcount) for dept in ([dept1],[dept2])) p
This does what I expect it to do, it gives me a count of incidents per reason with depts as my columns. My problem is the departments that I am using for my columns go from 1-60.
Is there anyway I can tell the query to use the column Department to populate the PIVOT in part. Obviously I want to avoid manually typing each department.
EDIT
This is the sql that creates my dataset that I use in the pivot...
SELECT Details, Department , count(*) NoIncidents
FROM myincidentdb
Group by Details, Department
EDIT 2
You will want to use dynamic sql to PIVOT this, your code will be similar to this:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(dept)
from yourtablewithDepartments
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT *
from
(
<your query goes here>
) src
pivot
(
max(incidentcount)
for dept in (' + #cols + ')
) piv '
execute(#query)
If you post more details like table structure, etc then this can be refined to meet your needs.
Edit, based on your current query, it looks like you can use the following:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#colsNull AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(department)
from myincidentdb
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Details, ' + #cols + '
from
(
select Details, Department
from myincidentdb
) x
pivot
(
count(Department)
for Department in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo