Horizontal Grand Total in Pivot Table SQL - sql

I have this query working:
select cap_idPlanoContasFin , [3684],[2234],[2] ,
from
(
select cap_idPlanoContasFin,cap_idempresa,sum(cap_valorfatura)
as Stotal
from erp_ContasPagar
group by cap_idPlanoContasFin , cap_idEmpresa
) as sourcetable
pivot
(sum(Stotal)for cap_idEmpresa in ([3684],[2234],[2])
)as pivottable;
This query returns:
cap_idPlanoContasFin 3684 2234 2
3 9000 NULL NULL
10 1057840,68 NULL 1865081,35
11 NULL 7283,1 591,9
12 NULL NULL 178914,45
13 9305,07 1117,6 500
14 NULL 59333,5 34611,74
I want to put in the same query the Horizontal Total
Example:
cap_idPlanoContasFin 3684 2234 2 Total
---------------------------------------------------------------------
13 9305,07 1117,6 500 10922,67
How to make this? I have read something with UNION.

First of all, you don't need to group your data beforehand: the PIVOT clause will do that for you. So you can remove the GROUP BY clause and change the SUM()'s argument in PIVOT accordingly:
select cap_idPlanoContasFin, [3684], [2234], [2]
from
(
select cap_idPlanoContasFin, cap_idempresa, cap_valorfatura
from erp_ContasPagar
group by cap_idPlanoContasFin , cap_idEmpresa
) as sourcetable
pivot
(
sum(cap_valorfatura) for cap_idEmpresa in ([3684], [2234], [2])
) as pivottable;
To add a total column, you could use a window SUM() like this:
select cap_idPlanoContasFin, [3684], [2234], [2], Total
from
(
select cap_idPlanoContasFin, cap_idempresa, cap_valorfatura,
sum(cap_valorfatura) over (partition by cap_idPlanoContasFin) as Total
from erp_ContasPagar
) as sourcetable
pivot
(
sum(cap_valorfatura) for cap_idEmpresa in ([3684], [2234], [2])
) as pivottable;
Note, however, that if your sourcetable includes rows with cap_idEmpresa values other than those listed in the PIVOT clause, the corresponding cap_valorfatura values will be added up too. So you might want to filter the sourcetable row set before pivoting, like this:
select cap_idPlanoContasFin, [3684], [2234], [2], Total
from
(
select cap_idPlanoContasFin, cap_idempresa, cap_valorfatura,
sum(cap_valorfatura) over (partition by cap_idPlanoContasFin) as Total
from erp_ContasPagar
where cap_idempresa in (3684, 2234, 2)
) as sourcetable
pivot
(
sum(cap_valorfatura) for cap_idEmpresa in ([3684], [2234], [2])
) as pivottable;

Thanks to all , this is the final query :
select cap_idPlanoContasFin, plc_classificador, plc_nomeConta,[3684], [2234], [2],
isnull ([2234],0) + isnull ([2],0) AS Subtotal ,Total
from
(
select A.cap_idempresa, A.cap_idPlanoContasFin, A.cap_valorfatura,
B.plc_classificador , B.plc_nomeConta,
sum(A.cap_valorfatura) over (partition by A.cap_idPlanoContasFin) as Total
from erp_ContasPagar A /*where cap_idempresa in (3684, 2234, 2)*/
inner join tbl_PlanoFinanceiro B on A.cap_idPlanoContasFin = B.plc_id
) as sourcetable
pivot
(
sum(cap_valorfatura) for cap_idEmpresa in ([3684], [2234], [2])
) as pivottable;
I need use isnull to change NULL by o to sume subtotal . Thanks again by the help

Related

How to get multiple values from a singe query in sql

I have a query like:
SELECT NUM,
PARAM_1
FROM STOCK_CARD_PARAMETER WITH(NOLOCK)
WHERE FK_STOCK_CARD IN (SELECT FK_sTOCK_CARD
FROM STOCK_BARCODE WITH(NOLOCK)
WHERE BARCODE = '2002002232364' )
And it returns:
NUM PARAM_1
1 İNDİRİMSİZ
2 SEZON
3 UNISEXYETISKIN
I have to get a result like that. (side by side)
İNDİRİMSİZ SEZON UNISEXYETISKIN
To do this, I execute almost the same query 2 times like this:
INDIRIM = (SELECT PARAM_1
FROM STOCK_CARD_PARAMETER WITH(NOLOCK)
WHERE FK_STOCK_CARD IN (SELECT FK_sTOCK_CARD
FROM STOCK_BARCODE WITH(NOLOCK)
WHERE BARCODE = #BARKOD AND NUM = 1)),
STATU = ( SELECT PARAM_1
FROM STOCK_CARD_PARAMETER WITH(NOLOCK)
WHERE FK_STOCK_CARD IN (SELECT FK_sTOCK_CARD
FROM STOCK_BARCODE WITH(NOLOCK)
WHERE BARCODE = #BARKOD AND NUM = 2))
NUM column is the key here. How do I make this two query combined and get the result side by side?
Using PIVOT
SELECT [1], [2], [3]
FROM
(SELECT NUM, PARAM_1
FROM table) AS SourceTable
PIVOT
(
MAX(PARAM_1)
FOR NUM IN ([1], [2], [3])
) AS PivotTable;
Sample data with output
WITH C(NUM, PARAM_1) AS(
SELECT 1 , N'İNDİRİMSİZ' UNION ALL
SELECT 2 , N'SEZON' UNION ALL
SELECT 3 , N'UNISEXYETISKIN'
)
SELECT [1], [2], [3]
FROM
(SELECT NUM, PARAM_1
FROM C) AS SourceTable
PIVOT
(
MAX(PARAM_1)
FOR NUM IN ([1], [2], [3])
) AS PivotTable;
Output
İNDİRİMSİZ SEZON UNISEXYETISKIN

SQL server Pivot on Multiple Columns

I am trying to pivot on multiple columns. I am using SQL server 2008. Here is what I have tried so far
CREATE TABLE #t ( id int, Rscd varchar(10),Accd varchar(10),position int)
INSERT INTO #t Values (10,'A','B',1)
INSERT INTO #t Values (10,'C','D',2)
Select id,[1],[2],[11],[12] FROM
(SELECT id, Rscd,Accd, position , position +10 as Aposition
From #t)
As query
PIVOT (MAX(Rscd )
FOR Position IN ([1],[2])) AS Pivot1
PIVOT (MAX(Accd )
FOR Aposition IN ([11],[12])) AS Pivot2
The below indicated is the result that I am getting
id 1 2 11 12
10 NULL C NULL D
10 A NULL B NULL
But the result that I am trying to achieve is ,
id 1 2 11 12
10 A C B D
Any help ? what is wrong in my code.
I would unpivot the columns into pairs first, then pivot them. Basically the unpivot process will convert the pairs of columns (rscd, position and accd, aposition) into rows, then you can apply the pivot. The code will be:
select id, [1], [2], [11], [12]
from
(
select id, col, value
from #t
cross apply
(
select rscd, position union all
select Accd, position + 10
) c (value, col)
) d
pivot
(
max(value)
for col in ([1], [2], [11], [12])
) piv;
See SQL Fiddle with Demo
Select id,sum([1]),sum([2]),sum([11]),sum([12]) FROM
(SELECT id, Rscd,Accd, position , position +10 as Aposition
From #t)
As query
PIVOT (MAX(Rscd )
FOR Position IN ([1],[2])) AS Pivot1
PIVOT (MAX(Accd )
FOR Aposition IN ([11],[12])) AS Pivot2
group by id
Dont Use the ID Column. Use a derived table to retrieve all columns except the ID and then use the PIVOT table.

SQL- pad results with extra rows

I have a group of records that have a "Store" column. I need to basically split the result sets into groups of 13 records, creating blank rows to pad out each store to have 13 rows.
For simplicity, lets say I need groups of 4 records.
Example, given the below table:
-----------------
Store Name
-----------------
A John
A Bill
B Sam
C James
C Tim
C Chris
D Simon
D Phil
I need the results to look like:
-----------------
Store Name
-----------------
A John
A Bill
A
B Sam
B
B
C James
C Tim
C Chris
D Simon
D Phil
D
Is this at all possible with pure SQL? There are never going to be more than 3 rows for each store.
SQL Fiddle
Try this one -
DDL:
SET STATISTICS IO ON;
IF OBJECT_ID (N'tempdb.dbo.#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
(
Store CHAR(1)
, Name VARCHAR(10)
)
INSERT INTO #temp (Store, Name)
VALUES
('A', 'John'), ('A', 'Bill'),
('B', 'Sam'), ('C', 'James'),
('C', 'Tim'), ('C', 'Chris'),
('D', 'Simon'), ('D', 'Phil')
Queries:
DevArt #1:
;WITH cte AS
(
SELECT
Store
, Name
, rn = ROW_NUMBER() OVER (PARTITION BY Store ORDER BY (SELECT 1))
FROM #temp
)
SELECT t.Store, Name = ISNULL(t3.Name, '')
FROM (
SELECT DISTINCT Store
FROM cte
) t
CROSS JOIN (SELECT rn = 1 UNION ALL SELECT 2 UNION ALL SELECT 3) t2
LEFT JOIN cte t3 ON t2.rn = t3.rn AND t.Store = t3.Store
DevArt #2:
SELECT t2.Store, Name = ISNULL(t3.Name, '')
FROM (
SELECT *
FROM (
SELECT Store, r = COUNT(1)
FROM #temp
GROUP BY Store
) t
CROSS APPLY (
VALUES (r), (r+1), (r+2)
) t2 (x)
) t2
LEFT JOIN #temp t3 ON t2.Store = t3.Store AND t2.x = t2.r
WHERE t2.x < 4
Alexander Fedorenko:
;WITH cte AS
(
SELECT DISTINCT Store
FROM #temp
)
SELECT o.Store, o.name
FROM cte s
CROSS APPLY (
SELECT TOP 3 x.Store, x.name
FROM (
SELECT s2.Store, s2.name
FROM #temp s2
WHERE s.Store = s2.Store
UNION ALL
SELECT s.Store, ''
UNION ALL
SELECT s.Store, ''
) x
) o
ErikE:
SELECT Store, Name
FROM (
SELECT
x.Store
, x.Name
, s = ROW_NUMBER() OVER (PARTITION BY x.Store ORDER BY x.s)
FROM #temp t
CROSS APPLY (
VALUES
(Store, Name, 0),
(Store, '', 1),
(Store, '', 1)
) x (Store, Name, S)
) z
WHERE s <= 3
ORDER BY Store
AmitSingh:
SELECT t.Store, Name = COALESCE(
(
SELECT name
FROM (
SELECT
row1 = ROW_NUMBER() OVER (PARTITION BY Store ORDER BY Store)
, *
FROM #temp
) c
WHERE t.[row] = c.row1
AND t.Store = c.Store
)
, '')
FROM
(
SELECT
[Row] = ROW_NUMBER() OVER (PARTITION BY a.Store ORDER BY a.Store)
, a.Store
FROM (
SELECT Store
FROM #temp
GROUP BY Store
) a
, (
SELECT TOP 3 Store
FROM #temp
) b
) t
Andriy M #1:
;WITH ranked AS
(
SELECT
Store
, Name
, rnk = ROW_NUMBER() OVER (PARTITION BY Store ORDER BY 1/0)
FROM #temp
)
, pivoted AS
(
SELECT
Store
, [1] = ISNULL([1], '')
, [2] = ISNULL([2], '')
, [3] = ISNULL([3], '')
FROM ranked
PIVOT (
MAX(Name)
FOR rnk IN ([1], [2], [3])
) p
)
, unpivoted AS
(
SELECT
Store
, Name
FROM pivoted
UNPIVOT (
Name FOR rnk IN ([1], [2], [3])
) u
)
SELECT *
FROM unpivoted
Andriy M #2:
;WITH ranked AS
(
SELECT
Store
, Name
, rnk = ROW_NUMBER() OVER (PARTITION BY Store ORDER BY 1/0)
FROM #temp
)
, padded AS
(
SELECT
Store
, Name
FROM ranked
PIVOT (
MAX(Name)
FOR rnk IN ([1], [2], [3])
) p
CROSS APPLY (
VALUES
(ISNULL([1], '')),
(ISNULL([2], '')),
(ISNULL([3], ''))
) x (Name)
)
SELECT *
FROM padded
Output:
Store Name
----- ----------
A John
A Bill
A
B Sam
B
B
C James
C Tim
C Chris
D Simon
D Phil
D
Statistics:
Query Presenter Scans Logical Reads
------------------- ----- -------------
DevArt #1 3 41
DevArt #2 2 9
Alexander Fedorenko 4 5
ErikE 1 1
AmitSingh 22 25
Andriy M #1 1 1
Andriy M #2 1 1
Query cost:
Extended statistics:
Execution statistics:
Query plan (from dbForge Studio for MS SQL):
Select t.store_id,Coalesce((Select Name from (
Select row_Number() Over(Partition by store_id order by store_id) as row1, * from stores)c
where t.row=c.row1 and t.store_id=c.store_id),'') as cfgg
from
(Select row_Number() Over(Partition by a.store_id order by a.store_id) as row,
a.store_id from
(Select store_id from stores group by store_id) a ,(Select top 3 store_id from stores)b
) t
SQL Fiddle Demo
One more option with APPLY operator
;WITH cte AS
(
SELECT store_id
FROM stores
GROUP BY store_id
)
SELECT o.store_id, o.name
FROM cte s CROSS APPLY (
SELECT TOP 3 x.store_id, x.name
FROM (
SELECT s2.store_id, s2.name
FROM stores s2
WHERE s.store_id = s2.store_id
UNION ALL
SELECT s.store_id, ''
UNION ALL
SELECT s.store_id, ''
) x
) o
Demo on SQLFiddle
Here's a query that works (SQL Server 2008 and up, can be fixed to work in 2005):
SELECT Store, Name
FROM (
SELECT
X.Store, X.Name, R = Row_Number() OVER (PARTITION BY X.Store ORDER BY X.S)
FROM
#temp T
CROSS APPLY (VALUES
(Store, Name, 0), (Store, '', 1), (Store, '', 1)
) X (Store, Name, S)
) Z
WHERE R <= 3
ORDER BY Store
;
According to SET STATISTICS IO ON;, here are performance statistics (all have negligible CPU at this low number of rows, perhaps more rows would help determine the best performer):
Query Presenter Scans Logical Reads
------------------- ----- -------------
ErikE 1 1
Alexander Fedorenko 4 5
Devart 3 41
AmitSingh 22 25
My query does not preserve the "original" ordering of the names for each store, however that is not a flaw because there is no concept of ordering in a relational database table. You must supply a column to order by if you want to preserve a particular sequence.
Yet another option, this time using PIVOT and UNPIVOT:
WITH ranked AS (
SELECT
store_id,
name,
rnk = ROW_NUMBER() OVER (PARTITION BY store_id ORDER BY 1/0)
FROM stores
),
pivoted AS (
SELECT
store_id,
[1] = ISNULL([1], ''),
[2] = ISNULL([2], ''),
[3] = ISNULL([3], '')
FROM ranked
PIVOT (
MAX(name) FOR rnk IN ([1], [2], [3])
) p
),
unpivoted AS (
SELECT
store_id,
name
FROM pivoted
UNPIVOT (
name FOR rnk IN ([1], [2], [3])
) u
)
SELECT *
FROM unpivoted
;
A SQL Fiddle demo to play with: http://sqlfiddle.com/#!3/354df/39.
Note that the UNPIVOT step in the above query has to be done in a separate SELECT from the PIVOT action. That is because UNPIVOT does not generate rows where columns listed in the IN column list contain NULLs. However, you could replace UNPIVOT with an equivalent technique (like CROSS APPLY) and thus move the unpivoting to the same subquery that does the pivoting:
WITH ranked AS (
SELECT
store_id,
name,
rnk = ROW_NUMBER() OVER (PARTITION BY store_id ORDER BY 1/0)
FROM stores
),
padded AS (
SELECT
store_id,
name
FROM ranked
PIVOT (
MAX(name) FOR rnk IN ([1], [2], [3])
) p
CROSS APPLY (
VALUES
(ISNULL([1], '')),
(ISNULL([2], '')),
(ISNULL([3], ''))
) x (name)
)
SELECT *
FROM padded
;
A SQL Fiddle demo for the modified version: http://sqlfiddle.com/#!3/354df/40.

SQL Server 2008 Reporting: Sum of Max of group

I have a table like this in the report designer:
Category: 1 2 3 4 Total
Max Amount: x y z c ?
I need to get the total of Max Amount, but expressions will not let me take Sum(Max(amount)), and the add total is disabled for this cell.
The max amount row is an expression that takes the max of each category. The source data has repeated values, so I just take the max. For example:
Category Amount
1 4.6
1 4.6
1 4.6
2 5
3 4
Other columns in the table are different, but amount will be the same so I cannot only select distinct values.
Maybe something like this:
SELECT
SUM(t1.maxAmout)
FROM
(
SELECT
MAX(t.Amout) AS maxAmout,
t.Category
FROM
yourTable AS t
GROUP BY
t.Category
) AS t1
You can also do it like this. If you are using sql server 2005+:
SELECT
pvt.[1],
pvt.[2],
pvt.[3],
(
pvt.[1]+
pvt.[2]+
pvt.[3]
) AS Total
FROM
(
SELECT
t.Category,
t.Amout
FROM
yourTable AS t
) AS SourceTable
PIVOT
(
MAX(Amout)
FOR Category IN([1],[2],[3])
) AS pvt
EDIT
If you have a 1000 categories. Then a dynamic pivot would be the best solution. So like this:
Test data
CREATE TABLE #T
(
Category INT,
Amout FLOAT
)
INSERT INTO #T
VALUES
(1,4.6),
(1,4.6),
(1,4.6),
(2,5),
(3,4)
Unique column names
DECLARE #cols VARCHAR(MAX)
DECLARE #colsTotal VARCHAR(MAX)
;WITH CTE
AS
(
SELECT
ROW_NUMBER() OVER(PARTITION BY t.Category ORDER BY t.Amout) AS RowNbr,
t.*
FROM
#T AS t
)
SELECT #cols = COALESCE(#cols + ','+QUOTENAME(Category),
QUOTENAME(Category)),
#colsTotal=COALESCE(#colsTotal + '+ISNULL('+QUOTENAME(Category)+',0)',
'ISNULL('+QUOTENAME(Category)+',0)')
FROM
CTE
WHERE
CTE.RowNbr=1
ORDER BY
Category
Dynamic pivot
DECLARE #query NVARCHAR(4000)=
N'SELECT
'+#cols+',
(
'+#colsTotal+'
) AS Total
FROM
(
SELECT
t.Category,
t.Amout
FROM
#T AS t
) AS SourceTable
PIVOT
(
MAX(Amout)
FOR Category IN('+#cols+')
) AS pvt'
EXECUTE(#query)
WITH
aggregate
AS
(
SELECT
category,
MAX(amount) AS max_amount
FROM
yourTable
GROUP BY
category
)
SELECT
MAX(CASE WHEN category = 1 THEN max_amount ELSE NULL END) AS [1],
MAX(CASE WHEN category = 2 THEN max_amount ELSE NULL END) AS [2],
MAX(CASE WHEN category = 3 THEN max_amount ELSE NULL END) AS [3],
MAX(CASE WHEN category = 4 THEN max_amount ELSE NULL END) AS [4],
SUM(max_amount) AS [total]
FROM
aggregate
The following returns a single value:
SELECT DISTINCT SUM(MAX(Amount)) OVER ()
FROM atable
GROUP BY Category
You could use this as a subquery calculating the value of the Total column.
Alternatively, TOP (1) could be used instead of DISTINCT (don't know why I couldn't think of it before):
SELECT TOP (1) SUM(MAX(Amount)) OVER ()
FROM atable
GROUP BY Category

what is wrong with this sql query using pivot

I am writing an sql query using pivot and I am getting following errors:
Msg 156, Level 15, State 1, Line 14
Incorrect syntax near the keyword 'select'.
Msg 102, Level 15, State 1, Line 14
Incorrect syntax near ')'.
and query I have written is :
select *
from (
select a.ID as id,
a.dataValue as value
from dbo.TableA a (nolock)
where a.ID in (select b.ID from dbo.TableB b(nolock))
and a.someOtherId = '4000'
and a.DT = '2/16/2011 12:00:00'
)as data
pivot
(
sum([value])
for [id] in (select ID from dbo.TableB (nolock))
) as pvt
Can anyone help me out on this?? Thanks in advance.
According to Microsoft's docs, you cannot use select after in: you must list the values manually.
[<column that contains the values that will become column headers>]
IN ( [first pivoted column], [second pivoted column],
... [last pivoted column])
) AS <alias for the pivot table>
Assuming that select b.ID from dbo.TableB b(nolock) returns 1,2,3, you can rewrite your code like this:
select *
from (
select a.ID as id,
a.dataValue as value
from dbo.TableA a (nolock)
where a.ID in (1,2,3)
and a.someOtherId = '4000'
and a.DT = '2/16/2011 12:00:00'
)as data
pivot
(
sum([value])
for [id] in ([1],[2],[3])
) as pvt
You cannot dynamically build the list of fields in the for in clause.
for [id] in (select ID from dbo.TableB (nolock))
This is not allowed. You must explicitly list the column names (Sorry)
Change: select ID from dbo.TableB
To: (Field1, field2, Field3) -- the actual names of the fields you want to return
Example:
-- Pivot table with one row and five columns
SELECT 'AverageCost' AS Cost_Sorted_By_Production_Days,
[0], [1], [2], [3], [4]
FROM
(SELECT DaysToManufacture, StandardCost
FROM Production.Product) AS SourceTable
PIVOT
(
AVG(StandardCost)
FOR DaysToManufacture IN ([0], [1], [2], [3], [4])
) AS PivotTable;