Expression in FOR section of PIVOT - sql

I'm trying to use PIVOT to get the total weight of purchases per product, broken down by year/month in columns. Something like this:
+------------+--------+--------+--------+
| ProductKey | Jan-14 | Feb-14 | Mar-14 | Etc...
+------------+--------+--------+--------+
| 10 | 5000 | 7000 | 3000 |
| 20 | 10000 | 8000 | 6000 |
| 30 | 250 | 500 | 400 |
+------------+--------+--------+--------+
This is my first time trying to use PIVOT, so not sure this is right:
PIVOT
(
SUM([PO_PurchaseOrderLines].[EstimatedWeight])
FOR
LEFT(DATENAME(MONTH,[PO_Date]),3) & "-" & RIGHT(YEAR([PO_Date]),2)
IN (Jan-14, Feb-14, Mar-14, Apr-14, May-14, Jun-14, Jul-14, Aug-14, Sep-14, Oct-14, Nov-14, Dec-14, Jan-15, Feb-15, Mar-15, Apr-15, May-15, Jun-15, Jul-15, Aug-15, Sep-15, Oct-15, Nov-15, Dec-15, Jan-16, Feb-16, Mar-16, Apr-16, May-16, Jun-16, Jul-16, Aug-16, Sep-16, Oct-16, Nov-16, Dec-16, Jan-17, Feb-17, Mar-17)
) AS POPivot
Running this results in:
[Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near the keyword 'LEFT'.
Is using an expression like this in the FOR section not possible? Is there something else incorrect?

Select *
From (
Select ProductKey
,Col = format(PO_Date,'MMM-yy')
,EstimatedWeight
From YourTable A
) A
Pivot (sum(EstimatedWeight) For [Col] in ([Jan-14],[Feb-14],[Mar-14]) ) p

You can't use an expression in the FOR section, it needs to be a column in the query you're trying to pivot. I recommend performing that operation and assigning the value to a column in your initial query and then referencing that column under FOR.

This is the Requested Dynamic Version
Declare #SQL varchar(max) = ''
Select #SQL = Stuff((Select ',' + QuoteName(Col)
From (Select Distinct Top 100
Col=format(PO_Date,'MMM-yy')
,Ord=format(PO_Date,'yyyy-MM')
From YourTable
Where PO_Date>=DateAdd(MONTH,-36,DateFromParts(Year(GetDate()),Month(GetDate()),1)) -- Adjust This Value +/-
Order By 2
) A For XML Path('')),1,1,'')
Select #SQL = '
Select *
From (
Select ProductKey
,Col = format(PO_Date,''MMM-yy'')
,EstimatedWeight
From YourTable A
) A
Pivot (sum(EstimatedWeight) For [Col] in (' + #SQL + ') ) p'
Exec(#SQL);

Related

Row values as column headings

How can I make the following sql result:
Be rendered in a result set like this
| ID | Chain Size | Length | Hook Type | Shortening Grab |
|-----|-----------------|---------|------------|-----------------|
| 163 | 7mm (1.5 tonne) | 1 metre | C Hook | Yes |
| 226 | 7mm (1.5 tonne) | 1 metre | C Hook | No |
| 247 | 7mm (1.5 tonne) | 1 metre | Latch Hook | No |
I know that the values in columns 2,4,6 and 8 (which I want to be headers) will be the same across all rows (but different depending on the initial query).
I believe the approach for what I want is through the use of PIVOT but really struggling to get the desired result.
Thanks
Assuming your source data actually looks like this:
Static Pivot
Select *
From YourTable
Pivot (max(attributeValue) For [attributeName] in ([Chain Size],[Length],[Hook Type],[Shortening Grab]) ) p
Returns
Dynamic Approach
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName([attributeName]) From Yourtable Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Select *
From YourTable
Pivot (max(attributeValue) For [attributeName] in (' + #SQL + ') ) p'
Exec(#SQL);
Returns
Notice, without an item for column sequence, you'll see that they are alphabetical.

SQL Server: UPDATE after pivot (unpivot needed?)

Two days ago I asked how to use pivot in SQL to transpose a table.
With your help I got it right, here the solution: SQL server: Transpose Rows to Columns (n:m relationship)
I'm running SQL Server 2012, with an OBDC-connection, programming in C#.
So now I have:
| mitID | Name | FamName | DOB | abtIDref | HV | PEV | Drive | Nex |
|-------|--------|---------|------------|----------|---------------|------------|------------|------------|
| 1 | Frank | Sinatra | 12.12.1915 | 1 | **30.5.2016** | | 05.06.2015 | 02.11.2015 |
| 2 | Robert | Downey | 4.4.1965 | 2 | 27.7.2014 | 01.01.2016 | 20.01.2015 | |
I get this with following SQL statement:
DECLARE #sql AS NVARCHAR(MAX)
DECLARE #cols AS NVARCHAR(MAX)
SELECT #cols = ISNULL(#cols + ',', '') + QUOTENAME(Descr)
FROM Faehigkeiten ORDER BY faeID
SET #sql = N'
SELECT mitID, Name, FamName, DOB, abtIDref, ' + #cols + '
FROM(
SELECT mitID, Name, FamName, DOB, abtIDref, [when], descr
FROM Mitarbeiter m
JOIN[Link - List] l ON m.mitID = l.mitIDref
JOIN Faehigkeiten f ON f.faeID = l.feaIDref
) a
PIVOT(MAX([when]) FOR descr IN(' + #cols + ')) p'
EXEC sp_executesql #sql
But when I enter a new date (shown in asterisk above), or change a name of a member, how do I save the data?
I thought about unpivot, but I have no idea how to use it in my case.
My solution would be to loop through all the rows and compare it to existing entries ... but that could take a long time with lots of members.
Can you point me in some direction, wether it is possible to UPDATE this an easy way? I only need UPDATE no INSERT since new rows are forbidden.
Right now I have no class for my members. I load my DataGridView in C# with the following code:
BindingSource bsMember = new BindingSource();
bsMember.DataSource = DBMember.Get();
dgv.DataSource = bsMember;
The DBMember.Get() returns a DataTable made with the above shown SQL code.
Sorry, I have no approach except my loop through each row :/
EDIT: The provided duplicate is hard for me to follow because of the JOIN in my SQL-code. Can i JOIN while updating?
Please consider helping me directly.

Dynamic Pivot table error

I am currently having trouble getting the following to work. I have a table, 'tbl_View', that exists in my database that has the column names of another table held in its rows (users are able to choose specific columns that they wish to display and their list of their choices is kept here).
I then want to create a view that will bring only each users specific column choices from the target table 'AREG' and would like to do so dynamically if possible.
Table Samples - AREG Column names:
ID | Text_1 | Text_2 | Text_3 | Text_4 etc...
tbl_View Data:
ViewID | lblValue | fldName | showYN | sOrder
10 | EANPR | YesNo8 | True | 80
10 | INSP_DATE| Date_1 | True | 81
10 | KG_DATE | Date_2 | True | 82
11 | Life | Num_13 | True | 35
11 | Area | Dimension_1 | True | 69
11 | Length | Dimension_2 | True | 70
11 | EANPR | YesNo8 | True | 80
12 | TRAVEL | Text_1 | True | 1
12 | SPILLLVE | Text_2 | True | 2
12 | SLOPE_PCT| Text_3 | True | 3
14 |Project_Name | Text_1 | True | 1
14 | Project Description | Text_2 | 2
code is:
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column
SELECT #ColumnName= ISNULL(#ColumnName + ',','') + QUOTENAME(fldName)
FROM (SELECT DISTINCT fldName FROM qry_ADet WHERE (Viewid=14)) AS fname
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery = N'SELECT ' + #ColumnName + ' FROM #AREG PIVOT ' + #ColumnName + ' AS PVTTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql #DynamicPivotQuery
I keep getting the error:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'Text_1'.
I have hard coded the view id into the query for this example but will use a parameter in my final query as it will be referenced by an asp.net datasource. But the error points to a different column name if you change the Viewid clause.
Please help.
Thanks
to debug a dynamic sql query, do a PRINT statement before executing it.
You will probably see that the error is from #DynamicPivotQuery
- you should be selecting from tbl_View instead of #AREG right ?
- your pivot statement is wrong. it should be something like
FROM sometable
PIVOT
(
sum( somecol)
for anothercol in ( [value1], [value2] , [value3] )
) p
too long for comment, I think the issue may stem from the column concatenation and it needs something like this:
SET #ColumnName = STUFF((SELECT distinct ',' + QUOTENAME(fldName)
FROM qry_ADet
WHERE (Viewid=14)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')

SQL Server Merge 2 rows into 1

Is it possible to merge 2 rows into a single row in SSRS 2008?
Each part will have a record for each site
+---------------+-------+-------+
|Part Number |Cost |Site |
+---------------+-------+-------+
|1 |2.4 |Site 1 |
|1 |68.8 |Site 2 |
+---------------+-------+-------+
Desired Result
+-----------+-------+-------+
|Part Number|Site 1 |Site 2 |
+-----------+-------+-------+
| 1 |2.4 |68.8 |
+-----------+-------+-------+
Thank you
If you know your site numbers/names will not change dynamically then can use CASE WHEN:s
SELECT PartNumber,
MAX(CASE WHEN Site=1 THEN Cost ELSE NULL END) AS Site1_Cost,
MAX(CASE WHEN Site=2 THEN Cost ELSE NULL END) AS Site2_Cost
FROM Parts
GROUP BY PartNumber
By grouping we eliminated a NULL values...
Here link with SQL Fiddle example
In SSRS to you need to use MATRIX report to convert rows into columns without using PIVOT operator
Suppose you have a table SSRSPivot
Create table SSRSPivot
(PartNumber int ,Cost decimal(18,2),Site varchar(max))
Insert into SSRSPivot
values
(1,2.4,'Site 1'),
(1,68.8,'Site 2' )
The data is in the below format
+---------------+-------+-------+
|PartNumber |Cost |Site |
+---------------+-------+-------+
|1 |2.4 |Site 1 |
|1 |68.8 |Site 2 |
+---------------+-------+-------+
Create a new blank report and name it as PIVOT.Create a datasource and in the dataset write the query
Select PartNumber ,Cost,Site from SSRSPivot
Drag a matrix from the toolbox onto the SSRS designer.For Rows select PartNumber .For columns select Site and for the data select Sum(Cost)
When you do the above step ,you will get the row and column details like the one below
Final Result will look like
This type of data transformation is known as a PIVOT. Starting in SQL Server 2005, there is a function that can transpose the data into columns for you.
If you have a known number of Site values that you want to turn into columns, then you can hard-code the query:
select part_number, [Site 1], [Site 2]
from
(
select part_number, cost, site
from yourtable
) src
pivot
(
sum(cost)
for site in ([Site 1], [Site 2])
) piv;
See SQL Fiddle with Demo
But if you have an unknown number of values, then you will need to use dynamic SQL to generate the column list to be used in the query:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(site)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT part_number,' + #cols + '
from
(
select part_number, cost, site
from yourtable
) x
pivot
(
sum(cost)
for site in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo. Both will give the result:
| PART_NUMBER | SITE 1 | SITE 2 |
---------------------------------
| 1 | 2.4 | 68.8 |

SQL Server 2005 Pivot on Unknown Number of Columns

I am working with a set of data that looks something like the following.
StudentName | AssignmentName | Grade
---------------------------------------
StudentA | Assignment 1 | 100
StudentA | Assignment 2 | 80
StudentA | Total | 180
StudentB | Assignment 1 | 100
StudentB | Assignment 2 | 80
StudentB | Assignment 3 | 100
StudentB | Total | 280
The name and number of assignments are dynamic, I need to get results simlilar to the following.
Student | Assignment 1 | Assignment 2 | Assignment 3 | Total
--------------------------------------------------------------------
Student A | 100 | 80 | null | 180
Student B | 100 | 80 | 100 | 280
Now ideally I would like to sort the column based on a "due date" that could be included/associated with each assignment. The total should be at the end if possible (It can be calculated and removed from the query if possible.)
I know how to do it for the 3 assignments using pivot with simply naming the columns, it is trying to do it in a dynamic fashion that I haven't found a GOOD solution for yet. I am trying to do this on SQL Server 2005
EDIT
Ideally I would like to implement this WITHOUT using Dynamic SQL, as that is against the policy. If it isn't possible...then a working example with Dynamic SQL will work.
I know you said no dynamic SQL, but I don't see any way to do it in straight SQL.
If you check out my answers to similar problems at Pivot Table and Concatenate Columns and PIVOT in sql 2005
The dynamic SQL there is not vulnerable to injection, and there is no good reason to prohibit it. Another possibility (if the data is changing very infrequently) is to do code-generation - instead of dynamic SQL, the SQL is generated to a stored procedure on a regular basis.
To PIVOT this data using dynamic sql you can use the following code in SQL Server 2005+:
Create Table:
CREATE TABLE yourtable
([StudentName] varchar(8), [AssignmentName] varchar(12), [Grade] int)
;
INSERT INTO yourtable
([StudentName], [AssignmentName], [Grade])
VALUES
('StudentA', 'Assignment 1', 100),
('StudentA', 'Assignment 2', 80),
('StudentA', 'Total', 180),
('StudentB', 'Assignment 1', 100),
('StudentB', 'Assignment 2', 80),
('StudentB', 'Assignment 3', 100),
('StudentB', 'Total', 280)
;
Dynamic PIVOT:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(AssignmentName)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT StudentName, ' + #cols + ' from
(
select StudentName, AssignmentName, grade
from yourtable
) x
pivot
(
min(grade)
for assignmentname in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo
The result is:
| STUDENTNAME | ASSIGNMENT 1 | ASSIGNMENT 2 | ASSIGNMENT 3 | TOTAL |
--------------------------------------------------------------------
| StudentA | 100 | 80 | (null) | 180 |
| StudentB | 100 | 80 | 100 | 280 |
The only way I've found to do this is to use dynamic SQL and put the column labels into a variable.
you could query information_schema to get the column names and types, then use the result as a subquery when you build your result set. Note you'll likely have to change the login's access a bit.
This is the same as PIVOT in sql 2005
If this data is for consumption in a report you could use a SSRS matrix. It will generate columns dynamically from result set. I've used it many times - it works quite well for dynamic crosstab reports.
Here's a good example w/ dynamic sql.
http://www.simple-talk.com/community/blogs/andras/archive/2007/09/14/37265.aspx
SELECT TrnType
INTO #Temp1
FROM
(
SELECT '[' + CAST(TransactionType AS VARCHAR(4)) + ']' AS TrnType FROM tblPaymentTransactionTypes
) AS tbl1
SELECT * FROM #Temp1
SELECT * FROM
(
SELECT FirstName + ' ' + LastName AS Patient, TransactionType, ISNULL(PostedAmount, 0) AS PostedAmount
FROM tblPaymentTransactions
INNER JOIN emr_PatientDetails ON tblPaymentTransactions.PracticeID = emr_PatientDetails.PracticeId
INNER JOIN tblPaymentTransactionDetails ON emr_PatientDetails.PatientId = tblPaymentTransactionDetails.PatientID
AND tblPaymentTransactions.TransactionID = tblPaymentTransactionDetails.TransactionID
WHERE emr_PatientDetails.PracticeID = 152
) tbl
PIVOT (SUM(PostedAmount) FOR [TransactionType] IN (SELECT * FROM #Temp1)
) AS tbl4
select studentname,[Assign1],[Assign2],[Assign3],[Total]
from
(
select studentname, assignname, grade from student
)s
pivot(sum(Grade) for assignname IN([Assign1],[Assign2],[Assign3],[Total])) as pvt