Issue with Syntax Pivoting Rows to Columns - sql

I am trying to pivot rows from one table into columns joined with other tables I am hoping can use in a view.
Here is the Statement:
DECLARE #columns NVARCHAR(MAX) = '';
SELECT #columns+=QUOTENAME(FFName) + ','
FROM TCG_LU_FUND_FAMILY_02
SET #columns = LEFT(#columns, LEN(#columns) - 1);
SELECT *
FROM(select F.PositionID as PID
, P.EmployeeName as EmployeeName
, P.Department as BUName
, P.Office as Office
, NULL as Team
, NULL as Manager
, P.Level as Level
, P.Title as Title
, P.HireDate as HireDate
, F.Headcount as HC
, Q.Average_Cost as Cost
, Q.Haircut as [Haircut %]
, F.Position_Filled_in_Qtr as [Position Filled during Quarter]
, F.Percent_Vacant as "Months in Qtr Position was VACANT 100%,66%,33%"
, F.Percent_Allocated
, FF.FFName as Fund_name
FROM TCG_RegisterFact_02 F
inner join TCG_LU_Position_02 P
on F.PositionID = P.PositionID
inner join TCG_LU_QUARTER_LEVEL_02 Q
on P.Level = Q.Level
inner join TCG_LU_FUND_FAMILY_02 FF
on F.FFName = FF.FFName
) as SrcTbl
PIVOT( sum (Percent_Allocated) FOR Fund_Name
in ('+ #columns +')) as PivTbl;
And here is the error message I receive:
Incorrect syntax near '+ #columns +'. (SQL Error Number -2146232060, 102)

Related

SQL - SUM the values from a COLUMN and put each value in a SEPARATE column

I have a simple join query for multiple tables that looks like this:
select
b.buyer_id,
v.vendor_id,
r.report_number,
sum(r.amount_fee),
f.fee_description
from buyer b
join vendor v on v.vendor_id = bu.vendor_id
join report r on r.report_num = bu.report_num
join fees f on f.report_num = r.report_num
group by b.buyer_id, v.vendor_id, r.report_number, f.fee_description
Which will show something like this:
But I want it to look like this:
Can you help me how to rewrite my script please?
Thanks alot!
If your fee descriptions are fixed, a simple PIVOT query will do the trick.
SELECT
buyer_id,
vendor_id,
report_number,
[Late Charge],
[Finance Charge],
[Reserve Fee],
[Additional Fee]
FROM
(
select b.buyer_id, v.vendor_id, r.report_number, r.amount_fee As AmountFee, f.fee_description
from buyer b
join vendor v on v.vendor_id = bu.vendor_id
join report r on r.report_num = bu.report_num
join fees f on f.report_num = r.report_num
) As s
PIVOT
(
Sum(AmountFee) FOR fee_description IN ([Late Charge], [Finance Charge], [Reserve Fee], [Additional Fee])
) As P
If the fee descriptions could change, you'll need a dynamic pivot query:
DECLARE #columns nvarchar(max);
SET #columns = STUFF
(
(SELECT DISTINCT N',' + QUOTENAME(fee_description)
FROM fees
ORDER BY fee_description
FOR XML PATH(''), TYPE)
.value('.', 'nvarchar(max)'),
1, 1, N''
);
DECLARE #sql nvarchar(max);
SET #sql = N'SELECT buyer_id, vendor_id, report_number, ' + #columns + N'
FROM
(
select b.buyer_id, v.vendor_id, r.report_number, r.amount_fee As AmountFee, f.fee_description
from buyer b
join vendor v on v.vendor_id = bu.vendor_id
join report r on r.report_num = bu.report_num
join fees f on f.report_num = r.report_num
) As s
PIVOT
(
Sum(AmountFee) FOR fee_description IN (' + #columns + N')
) As P';
EXEC sp_executesql #sql;

SQL Server query result by column to row

This is my sample code:
SQL Fiddle
I need it to result like this:
category outlet1 outlet2 outlet3
Sale 70 20 40
Expense 250 130 200
How can I do this?
EDIT: My outlets are not fixed, sorry for not telling this beforehand.
You can solve your particular problem using conditional aggregation:
SELECT c.category,
SUM(CASE WHEN o.outletname = 'Outlet1' THEN t.amt ELSE 0 END) as Outlet1,
SUM(CASE WHEN o.outletname = 'Outlet2' THEN t.amt ELSE 0 END) as Outlet2,
SUM(CASE WHEN o.outletname = 'Outlet3' THEN t.amt ELSE 0 END) as Outlet3
FROM tblcategory c INNER JOIN
tbltran t
ON t.catid = c.id INNER JOIN
tbloutlet o
ON o.id = t.outletid
GROUP BY c.category;
If the outlet names are not fixed, then you need dynamic SQL. The problem cannot be solve using a single SELECT query.
Here with dynamic Outlets http://sqlfiddle.com/#!18/a7b09/25
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(outletname)
from tbloutlet
group by outletname
order by outletname
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT category,' + #cols + ' from
(
SELECT c.category, o.outletname, SUM(t.amt) as amt
FROM tblcategory c
INNER JOIN tbltran t ON t.catid = c.id
INNER JOIN tbloutlet o ON o.id = t.outletid
GROUP BY c.category, o.outletname
) x
pivot
(
sum(amt)
for outletname in (' + #cols + ')
) p '
execute(#query);
you may also use the PIVOT operator
SELECT *
FROM
(
SELECT category, outletname, amt
FROM tblcategory c
INNER JOIN tbltran t ON t.catid = c.id
INNER JOIN tbloutlet o ON o.id = t.outletid
) d
PIVOT
(
SUM(amt)
FOR outletname in ([Outlet1] , [Outlet2] , [Outlet3])
) p
EDIT : below is the Dynamic SQL version
declare #Outlets nvarchar(max),
#SQL nvarchar(max)
select #Outlets = isnull(#Outlets + ',', '') + quotename(outlet)
from outlet
select #SQL = '
SELECT *
FROM
(
SELECT category, outletname, amt
FROM tblcategory c
INNER JOIN tbltran t ON t.catid = c.id
INNER JOIN tbloutlet o ON o.id = t.outletid
) d
PIVOT
(
SUM(amt)
FOR outletname in (' + #Outlets + ')
) p'
print #SQL -- print out for verification
exec sp_executesql #SQL

Concatenate Each Row column values into string with comma seperated in SQL

I'm using the AdventureWorks2008R2 sample database.
i need an output like each row should be concatenated into string(column values will be separated by commas)
This is my code:
create proc sales5
as begin
declare #SalesPersonID int
create table #table
(
id int identity(1,1) primary key clustered,
SalesPersonID int
)
create table #table1
(
SalesPersonID int null ,
PostalCode nvarchar (15) null,City varchar (30) null
)
insert into #table
select distinct
SA.BusinessEntityID
from
Sales.SalesPerson SA
join
Sales.SalesOrderHeader S on S.SalesPersonID = SA.BusinessEntityID
and S.SalesPersonID is not null
;WITH CTE
AS (
SELECT DISTINCT s.SalesPersonID
, CAST(A.PostalCode AS NVARCHAR(25)) AS PostalCode
, A.City
, CAST(s.SalesPersonID AS VARCHAR(MAX)) AS SortOrder
FROM Sales.SalesOrderHeader S(NOLOCK)
, Person.Person P(NOLOCK)
, Person.Address A(NOLOCK)
, #table t
WHERE s.SalesPersonID IS NOT NULL
AND S.SalesPersonID = P.BusinessEntityID
AND S.SalesPersonID = A.AddressID
AND S.SalesPersonID IN ('274')
UNION ALL
SELECT a.SalesOrderID
, a.SalesOrderNumber
, NULL
, C.SortOrder + CAST(a.SalesOrderID AS VARCHAR(MAX))
FROM CTE C
INNER JOIN Sales.SalesOrderHeader A(NOLOCK)
ON A.SalesPersonID = C.SalesPersonID
)
SELECT *
FROM cte
union all
select
cast ( P.BusinessEntityID as nvarchar(50)),
cast (P.NationalIDNumber as nvarchar(30)),
cast (P.Gender as nvarchar(20)),
cast (P.BusinessEntityID as VARCHAR(MAX)) + cast ('1' as VARCHAR(MAX))
from HumanResources.Employee P(nolock)
where exists(
select 1 from CTE C
where P.BusinessEntityID=C.SalesPersonID )
ORDER BY SortOrder
set nocount off
end
My output is like :
SalesPersonID PostalCode City SortOrder
274 98027 Issaquah 274
274 502097814 M 2741
43849 SO43849 NULL 27443849
44082 SO44082 NULL 27444082
44508 SO44508 NULL 27444508
44532 SO44532 NULL 27444532
My Expected Output:
274,98027,Issaquah
274,502097814,M
43849,SO43849
44082,SO44082
44508,SO44508
44532,SO44532
Note:no need of sortorder Column ,thats y i necglected in output.
Any one please help on this..
Thanks in advance.
You can concatenate your result using + or CONCAT like this.
SELECT LTRIM(SalesPersonID) + ',' + LTRIM(PostalCode) + ISNULL(',' + LTRIM(City),'')
FROM CTE2
ORDER BY SortOrder
Complete Query
;WITH CTE
AS (
SELECT DISTINCT s.SalesPersonID
, CAST(A.PostalCode AS NVARCHAR(25)) AS PostalCode
, A.City
, CAST(s.SalesPersonID AS VARCHAR(MAX)) AS SortOrder
FROM Sales.SalesOrderHeader S(NOLOCK)
, Person.Person P(NOLOCK)
, Person.Address A(NOLOCK)
, #table t
WHERE s.SalesPersonID IS NOT NULL
AND S.SalesPersonID = P.BusinessEntityID
AND S.SalesPersonID = A.AddressID
AND S.SalesPersonID IN ('274')
UNION ALL
SELECT a.SalesOrderID
, a.SalesOrderNumber
, NULL
, C.SortOrder + CAST(a.SalesOrderID AS VARCHAR(MAX))
FROM CTE C
INNER JOIN Sales.SalesOrderHeader A(NOLOCK)
ON A.SalesPersonID = C.SalesPersonID
), CTE2 as
(
SELECT *
FROM cte
union all
select
cast ( P.BusinessEntityID as nvarchar(50)),
cast (P.NationalIDNumber as nvarchar(30)),
cast (P.Gender as nvarchar(20)),
cast (P.BusinessEntityID as VARCHAR(MAX)) + cast ('1' as VARCHAR(MAX))
from HumanResources.Employee P(nolock)
where exists(
select 1 from CTE C
where P.BusinessEntityID=C.SalesPersonID )
)
SELECT LTRIM(SalesPersonID) + ',' + LTRIM(PostalCode) + ISNULL(',' + LTRIM(City),'')
FROM CTE2
ORDER BY SortOrder

T:SQL: select values from rows as columns

I have a table for Profiles stores profile properties values in row style, ex:
[ProfileID] [PropertyDefinitionID] [PropertyValue]
1 6 Jone
1 7 Smith
1 8 Mr
1 3 50000
and another table for property definitions :
[PropertyDefinitionID] [PropertyName]
6 FirstName
7 LastName
8 Prefix
3 Salary
How to use PIVOT or any other way to show it in this way:
[ProfileID] [FirstName] [LastName] [Salary]
1 Jone Smith 5000
It's easy to do this without PIVOT keyword, just by grouping
select
P.ProfileID,
min(case when PD.PropertyName = 'FirstName' then P.PropertyValue else null end) as FirstName,
min(case when PD.PropertyName = 'LastName' then P.PropertyValue else null end) as LastName,
min(case when PD.PropertyName = 'Salary' then P.PropertyValue else null end) as Salary
from Profiles as P
left outer join PropertyDefinitions as PD on PD.PropertyDefinitionID = P.PropertyDefinitionID
group by P.ProfileID
you can also do this with PIVOT keyword
select
*
from
(
select P.ProfileID, P.PropertyValue, PD.PropertyName
from Profiles as P
left outer join PropertyDefinitions as PD on PD.PropertyDefinitionID = P.PropertyDefinitionID
) as P
pivot
(
min(P.PropertyValue)
for P.PropertyName in ([FirstName], [LastName], [Salary])
) as PIV
UPDATE: For dynamic number of properties - take a look at Increment value in SQL SELECT statement
It looks like you might have an unknown number of PropertyName's that you need to turn into columns. If that is the case, then you can use dynamic sql to generate the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(PropertyName)
from propertydefinitions
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT profileid, ' + #cols + ' from
(
select p.profileid,
p.propertyvalue,
d.propertyname
from profiles p
left join propertydefinitions d
on p.PropertyDefinitionID = d.PropertyDefinitionID
) x
pivot
(
max(propertyvalue)
for propertyname in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo.

How to declare the columns dynamically in a Select query using PIVOT

I am writing a query to get the address for PersonID. Following query is working for me but it only returns with two Addresses. I want to handle the 'n' number of address with a single query. Is there any way to do this?
Many thanks
SELECT
PersonID, PersonName
[Address1], [Address2]
FROM
(
SELECT
P.PersonID,
P.PersonName,
(ROW_NUMBER() OVER(PARTITION BY P.PersonID ORDER BY A.AddressID)) RowID
FROM tblPerson
INNER JOIN tblAddress AS A ON A.PersonID = P.PersonID
) AS AddressTable
PIVOT
(
MAX(AddressID)
FOR RowID IN ([Address1], [Address2])
) AS PivotTable;
Assuming the following tables and sample data:
USE tempdb;
GO
CREATE TABLE dbo.tblPerson(PersonID INT, PersonName VARCHAR(255));
INSERT dbo.tblPerson SELECT 1, 'Bob'
UNION ALL SELECT 2, 'Charlie'
UNION ALL SELECT 3, 'Frank'
UNION ALL SELECT 4, 'Amore';
CREATE TABLE dbo.tblAddress(AddressID INT, PersonID INT, [Address] VARCHAR(255));
INSERT dbo.tblAddress SELECT 1,1,'255 1st Street'
UNION ALL SELECT 2,2,'99 Elm Street'
UNION ALL SELECT 3,2,'67 Poplar Street'
UNION ALL SELECT 4,2,'222 Oak Ave.'
UNION ALL SELECT 5,1,'36 Main Street, Suite 22'
UNION ALL SELECT 6,4,'77 Sicamore Ct.';
The following query gets the results you want, and shows how it handles 0, 1 or n addresses. In this case the highest number is 3 but you can play with more addresses if you like by adjusting the sample data slightly.
DECLARE #col NVARCHAR(MAX) = N'',
#sel NVARCHAR(MAX) = N'',
#from NVARCHAR(MAX) = N'',
#query NVARCHAR(MAX) = N'';
;WITH m(c) AS
(
SELECT TOP 1 c = COUNT(*)
FROM dbo.tblAddress
GROUP BY PersonID
ORDER BY c DESC
)
SELECT #col = #col + ',[Address' + RTRIM(n.n) + ']',
#sel = #sel + ',' + CHAR(13) + CHAR(10) + '[Address' + RTRIM(n.n) + '] = x'
+ RTRIM(n.n) + '.Address',
#from = #from + CHAR(13) + CHAR(10) + ' LEFT OUTER JOIN xMaster AS x'
+ RTRIM(n.n) + ' ON x' + RTRIM(n.n) + '.PersonID = p.PersonID AND x'
+ RTRIM(n.n) + '.rn = ' + RTRIM(n.n)
FROM m CROSS JOIN (SELECT n = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_columns) AS n WHERE n.n <= m.c;
SET #query = N';WITH xMaster AS
(
SELECT PersonID, Address,
rn = ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Address)
FROM dbo.tblAddress
)
SELECT PersonID, PersonName' + #col
+ ' FROM
(
SELECT p.PersonID, p.PersonName, ' + STUFF(#sel, 1, 1, '')
+ CHAR(13) + CHAR(10) + ' FROM dbo.tblPerson AS p ' + #from + '
) AS Addresses;';
PRINT #query;
--EXEC sp_executesql #query;
If you print the SQL you will see this result:
;WITH xMaster AS
(
SELECT PersonID, Address,
rn = ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Address)
FROM dbo.tblAddress
)
SELECT PersonID, PersonName,[Address1],[Address2],[Address3] FROM
(
SELECT p.PersonID, p.PersonName,
[Address1] = x1.Address,
[Address2] = x2.Address,
[Address3] = x3.Address
FROM dbo.tblPerson AS p
LEFT OUTER JOIN xMaster AS x1 ON x1.PersonID = p.PersonID AND x1.rn = 1
LEFT OUTER JOIN xMaster AS x2 ON x2.PersonID = p.PersonID AND x2.rn = 2
LEFT OUTER JOIN xMaster AS x3 ON x3.PersonID = p.PersonID AND x3.rn = 3
) AS Addresses;
If you execute it, you will see this:
I know the query to get here is an ugly mess, but your requirement dictates it. It would be easier to return a comma-separated list as I suggested in my comment, or to have the presentation tier deal with the pivoting.