Related
I am new in SQL basically i required Sum result in separate columns as per different elements.
Please find my table and required result in below image.
Please guide me with regards to SQL query which give me the required result.
You can use conditional aggregation:
select payment,
sum(case when product = 'A' then amount else 0 end) as a,
sum(case when product = 'B' then amount else 0 end) as b,
sum(case when product = 'C' then amount else 0 end) as c,
sum(case when product = 'D' then amount else 0 end) as d,
sum(amount) as total
from t
group by payment;
You can use PIVOT to get the desired result
SELECT * ,
[A] + [B] + [C] + [D] AS Total
FROM ( SELECT Payment, Product, Amount FROM Your_Table) tr
PIVOT( SUM(Amount) FOR Product IN ( [A], [B], [C], [D] ) ) p;
You can use dynamic SQL pivot query if your products are not limited with A,B,C and D
Here is a sample query for SQL Server
DECLARE #products nvarchar(max)
SELECT #products =
STUFF(
(
select distinct ',[' + product + ']'
from Payments
for xml path('')
),
1,1,'')
declare #sql nvarchar(max)
set #sql = '
SELECT
*
FROM (
SELECT
Payment AS '' '',
Product,
Amount
from Payments
) Data
PIVOT (
SUM(Amount)
FOR Product
IN (
' + #products + '
)
) PivotTable'
exec sp_executesql #sql
Below is sample data
IF OBJECT_ID('tempdb..#t')IS NOT NULL
DROp TABLE #t
;with cte (Payment,Product,Amount)
AS
(
SELECT 'Cash','A',1 UNION ALL
SELECT 'Credit','B',2 UNION ALL
SELECT 'Credit','C',3 UNION ALL
SELECT 'Cash','D',5 UNION ALL
SELECT 'Cash','A',6 UNION ALL
SELECT 'Credit','B',23 UNION ALL
SELECT 'Credit','C',7 UNION ALL
SELECT 'Cash','D',11 UNION ALL
SELECT 'Cash','A',12 UNION ALL
SELECT 'Credit','B',14 UNION ALL
SELECT 'Credit','C',16 UNION ALL
SELECT 'Cash','D',26
)
SELECT * INTO #t FROM cte
Using Dynamic Sql
DECLARE #DyColumn Nvarchar(max),
#Sql Nvarchar(max),
#ISNULLDyColumn Nvarchar(max),
#SumCol Nvarchar(max)
SELECT #DyColumn=STUFF((SELECT DISTINCT ', '+QUOTENAME(Product) FROM #t FOR XML PATH ('')),1,1,'')
SELECT #ISNULLDyColumn=STUFF((SELECT DISTINCT ', '+'ISNULL('+QUOTENAME(Product)+',''0'')' +' AS '+QUOTENAME(Product) FROM #t FOR XML PATH ('')),1,1,'')
SELECT #SumCol=STUFF((SELECT DISTINCT ' + '+QUOTENAME(Product) FROM #t FOR XML PATH ('')),1,2,'')
SET #Sql='
SELECT *,('+#SumCol+') AS Total FROM
(
SELECT Payment,'+#ISNULLDyColumn+'
FROM
(
SELECT * FROM #t
)AS
SRC
PIVOT
(
SUM(AMOUNT) FOR Product IN ('+#DyColumn+')
) AS Pvt
)dt
'
PRINT #Sql
EXECUTE (#Sql)
Result
Payment A B C D Total
---------------------------------
Cash 19 0 0 42 61
Credit 0 39 26 0 65
mysql table:
table_results:
id results
1 1 0 1 2 4 5
2 5 4 2 6
3 7 2 8 2 4
I'm creating a Yii gridview I need to
SELECT SUM(results) AS results2 FROM table_results WHERE id = 1:
for example I have to sum first row: 1+0+1+2+4+5 and make as results2 which = 15.
How to do that just in sql?
There is no need for dynamic SQL. You can use:
SqlFiddleDemo
SELECT sub.id, SUM(sub.val) AS `sum`
FROM
(
SELECT id, SUBSTRING_INDEX(SUBSTRING_INDEX(t.results, ' ', n.n), ' ', -1) AS val
FROM table_results t
CROSS JOIN
(
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
) n
WHERE n.n <= 1 + (LENGTH(t.results) - LENGTH(REPLACE(t.results, ' ', '')))
) sub
-- WHERE sub.id = 1
GROUP BY sub.id
One way to do this is using dynamic SQL. So, entirely within MySQL:
declare #sql varchar(2000);
select #sql = concat('select ', replace(results, ' ', '+'))
from table_results tr
where id = 1;
prepare s from #sql;
execute s;
deallocate prepare s;
As a note: Just because I answered the question does not mean that I condone the data structure.
I have a problem to build a query. After searching on stackoverflow i think i need a crosstab. But i don't know what exactly is this. I think it would be quicker if i show you a simplified version of my problem. I would be glad if you could point me to right direction.
This is example of data:
ColumnIDToGroup Value
-----------------------
1 AAAA
1 BBBB
2 AAAA
2 BBBB
2 CCCC
I need to build a query to get the data in this format:
ColumnIDToGroup Value1 Value2 Value3 Value4 Value5
------------------------------------------------------------
1 AAAA BBBB 'Empty' 'Empty' 'Empty'
2 AAAA BBBB CCCC 'Empty' 'Empty'
As a workarround, I could accept this output, if it is simple to build (when a value is not null, it always have the same size)
ColumnIDToGroup ValueConcat
-------------------------------------
1 AAAABBBB************
2 AAAABBBBCCCC********
SAMPLE TABLE
CREATE TABLE #TEMP(ColumnIDToGroup INT,Value VARCHAR(30))
INSERT INTO #TEMP
SELECT 1, 'AAAA'
UNION ALL
SELECT 1, 'BBBB'
UNION ALL
SELECT 2, 'AAAA'
UNION ALL
SELECT 2, 'BBBB'
UNION ALL
SELECT 2, 'CCCC'
Now select the rows from the table, create a column for Value1, Value2 etc and select the extra columns for Value4,Value5 by UNION all and set text to Empty.
SELECT *,
'Value'+CAST(ROW_NUMBER() OVER(PARTITION BY ColumnIDToGroup ORDER BY VALUE)AS VARCHAR(3)) COL
INTO #NEWTABLE
FROM #TEMP
UNION ALL
SELECT 1,'Empty','Value3'
UNION ALL
SELECT 2,'Empty','Value3'
UNION ALL
SELECT 1,'Empty','Value4'
UNION ALL
SELECT 2,'Empty','Value4'
UNION ALL
SELECT 1,'Empty','Value5'
UNION ALL
SELECT 2,'Empty','Value5'
Now get the columns for pivot
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + COL + ']', '[' + COL + ']')
FROM (SELECT DISTINCT COL FROM #NEWTABLE) PV
ORDER BY COL
Now pivot the query
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT * FROM
(
SELECT *
FROM #NEWTABLE
) x
PIVOT
(
MIN(VALUE)
FOR COL IN (' + #cols + ')
) p
ORDER BY ColumnIDToGroup;'
EXEC SP_EXECUTESQL #query
Click here to view the result
If you want in the second specified format, you can use the below query
;WITH CTE AS
(
SELECT *
FROM #TEMP
UNION ALL
SELECT 1,'****'
UNION ALL
SELECT 2,'****'
UNION ALL
SELECT 1,'****'
UNION ALL
SELECT 2,'****'
UNION ALL
SELECT 1,'****'
UNION ALL
SELECT 2,'****'
UNION ALL
SELECT 1,'****'
UNION ALL
SELECT 1,'***'
)
SELECT DISTINCT C2.ColumnIDToGroup,
-- Convert to single row for each ColumnIDToGroup
SUBSTRING(
(SELECT ' ' + CTE.VALUE
FROM CTE
WHERE C2.ColumnIDToGroup=ColumnIDToGroup
ORDER BY
CASE WHEN CTE.VALUE = 'AAAA' THEN 1
WHEN CTE.VALUE = 'BBBB' THEN 2
WHEN CTE.VALUE = 'CCCC' THEN 3
ELSE 4
END
FOR XML PATH('')),2,200000) ValueConcat
FROM CTE C2
Click here to view result
I have three tables. I need to swith row values into columns.
Table-1: [Approval_Type]
App_ID Type_Ds
2 RMC2
1 RMC1
Table 2: [Project]
Pro_id Summary
1 PROJECT1
2 PROJECT2
Table:3 [Prj_App]
App_Id Pro_Id ExpDt ComDt
1 2 2010-06-05 2010-07-06
1 1 1999-05-05 1999-05-06
2 1 1900-01-01 1900-01-05
I want to display my result as
Pro_Id RMC2 RMC2ExpeDt RMC2ComDt RMC1 RMC1ExpeDt RMC1ComDt
1 RMC2 1900-01-01 1900-01-05 RMC1 1999-05-05 1999-05-06
2 NULL NULL NULL RMC1 2010-06-05 2010-07-06
Below is my query which returns'
DECLARE #SQL1 NVARCHAR(MAX) = ''
DECLARE #SQL NVARCHAR(MAX) = ''
SELECT #SQL1 = STUFF((SELECT ',' + QUOTENAME(Type_Ds) + ',' + QUOTENAME(Type_Ds + ' Expected Date') + ',' + QUOTENAME(Type_Ds + ' Completed Date')
from dbo.AppType
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
print #SQL1
SET #SQL = 'SELECT *
FROM ( SELECT A.Pro_Id,
Type_DS
FROM dbo.Project A left join [dbo].[Prj_App] B on A.Pro_id = B.Pro_Id
right outer join dbo.AppType C on B.App_Id = C.App_ID
) data
PIVOT
( MAX(Type_DS)
FOR Type_DS IN (' + #SQL1 + ')
) pvt1
where Pro_Id is not null'
print #SQL
EXECUTE SP_EXECUTESQL #SQL
Pro_Id RMC2 RMC2ExpeDt RMC2ComDt RMC1 RMC1ExpeDt RMC1ComDt
1 RMC2 NULL NULL RMC1 NULL NULL
2 NULL NULL NULL RMC1 NULL NULL.
can anyone help on it...
My suggestion when you are working with dynamic SQL is to always write the query hard-coded first, so you can get the logic correct, then convert it to dynamic SQL.
Since you are attempting to pivot 3 columns of data I would first unpivot the type_ds, expdt and comdt` columns, then apply the PIVOT function.
The hard-coded version of the query will be:
SELECT *
FROM
(
select pro_id,
type_ds = case
when col ='type_ds'
then type_ds
else type_ds+col end,
value
from
(
SELECT A.Pro_Id,
c.Type_DS,
convert(varchar(10), b.ExpDt, 120) ExpDt,
convert(varchar(10), b.ComDt, 120) ComDt
FROM dbo.Project A
left join [dbo].[Prj_App] B
on A.Pro_id = B.Pro_Id
right outer join dbo.Approval_Type C
on B.App_Id = C.App_ID
) s
cross apply
(
select 'type_ds', type_ds union all
select 'expdt', expdt union all
select 'comdt', comdt
) c (col, value)
) data
PIVOT
(
MAX(value)
FOR Type_DS IN (RMC2, RMC2expdt, RMC2comdt,
RMC1, RMC1expdt, RMC1comdt)
) pvt1
See SQL Fiddle with Demo. Now that you have a working version of the query, you can easily convert it to dynamic SQL:
DECLARE #SQL1 NVARCHAR(MAX) = ''
DECLARE #SQL NVARCHAR(MAX) = ''
SELECT #SQL1 = STUFF((SELECT ',' + QUOTENAME(Type_Ds) + ',' + QUOTENAME(Type_Ds + 'ExpDt') + ',' + QUOTENAME(Type_Ds + 'ComDt')
from dbo.Approval_Type
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #SQL = 'SELECT *
FROM
(
select pro_id,
type_ds = case
when col =''type_ds''
then type_ds
else type_ds+col end,
value
from
(
SELECT A.Pro_Id,
c.Type_DS,
convert(varchar(10), b.ExpDt, 120) ExpDt,
convert(varchar(10), b.ComDt, 120) ComDt
FROM dbo.Project A
left join [dbo].[Prj_App] B
on A.Pro_id = B.Pro_Id
right outer join dbo.Approval_Type C
on B.App_Id = C.App_ID
) s
cross apply
(
select ''type_ds'', type_ds union all
select ''expdt'', expdt union all
select ''comdt'', comdt
) c (col, value)
) data
PIVOT
(
MAX(value)
FOR Type_DS IN (' + #SQL1 + ')
) pvt1 '
--print #SQL
EXECUTE SP_EXECUTESQL #SQL
See SQL Fiddle with Demo
I have a SQL table like this:
CC Descr C_NO Vol Wt
2050 Des1 123 20 40
2060 Des2 123 30 50
2050 Des1 125 20 40
2060 Des2 125 30 50
2050 Des1 126 20 40
and I want output like this:
2050
Des1
123
20
40
125
20
40
126
20
40
2060
Des2
123
30
50
125
30
50
How can I do that using TSQL code?
For every similar CC value which always have similar Descr value, it shows all the C_No, Vol and Wt values related to that particular CC value in the sequence written in the output section.
Try this
DECLARE #t TABLE
(
CC BIGINT,
Descr NVARCHAR(10),
C_NO INT,
Vol SMALLINT,
WT SMALLINT
)
INSERT INTO #t(CC,Descr,C_NO,Vol,WT)
VALUES (2050,'Des1',123,20,40)
,(2060,'Des2',123,30,50)
,(2050,'Des1',125,20,40)
,(2060,'Des2',125,30,50)
,(2050,'Des1',126,20,40)
;WITH CTE1 AS(
SELECT
t1.CC
,t1.Descr
,MergedColumn = STUFF(
(SELECT
','
+ CAST(C_NO AS VARCHAR(10)) + '/' + CAST(Vol AS VARCHAR(10)) + '/' + CAST(Wt AS VARCHAR(10))
FROM #t AS t2
WHERE t2.CC=t1.CC AND t2.Descr=t2.Descr
FOR XML PATH('')),1,1,'')
FROM #t t1
GROUP BY t1.CC,t1.Descr)
,CTE2 AS
(
SELECT
X.CC
,X.Descr
,Y.SplitDataByComma
FROM
(
SELECT
*,
CAST('<X>'+REPLACE(F.MergedColumn,',','</X><X>')+'</X>' AS XML) AS xmlfilter
FROM CTE1 F
)X
CROSS APPLY
(
SELECT fdata.D.value('.','varchar(50)') AS SplitDataByComma
FROM X.xmlfilter.nodes('X') AS fdata(D)
)Y
)
,CTE3 AS
(
SELECT
X.CC
,X.Descr
,Y.SplitDataBySlash
, X.SplitDataByComma AS GrpID
,ROW_NUMBER() OVER( PARTITION BY X.SplitDataByComma ORDER BY X.CC,X.Descr ) AS Rn
,X.SplitDataByComma + CAST(CC AS Varchar(200)) + CAST(Descr AS Varchar(200)) CC_Descr
FROM
(
SELECT
*,
CAST('<X>'+REPLACE(F.SplitDataByComma,'/','</X><X>')+'</X>' AS XML) AS xmlfilter
FROM CTE2 F
)X
CROSS APPLY
(
SELECT fdata.D.value('.','varchar(50)') AS SplitDataBySlash
FROM X.xmlfilter.nodes('X') AS fdata(D)
)Y
)
,CTE4 AS
(
SELECT
Rn = ROW_NUMBER() OVER(PARTITION BY CC ORDER BY CC)
,CC
,Descr
,CASE WHEN Rn = 1 THEN CAST (SplitDataBySlash AS VARCHAR(10)) ELSE ' ' END C_NO
,CASE WHEN Rn = 1 THEN ' ' ELSE CAST (SplitDataBySlash AS VARCHAR(10)) END Vol_Wt
,GrpID
FROM Cte3
)
,CTE5 AS(
SELECT
CC = CASE WHEN Rn > 1 THEN ' ' ELSE CAST(CC AS Varchar(200)) END
,Descr = CASE WHEN Rn > 1 THEN ' ' ELSE CAST(Descr AS Varchar(200)) END
,C_NO
,Vol_Wt
,GrpID
FROM Cte4)
SELECT
CHAR(10)
+ REPLICATE(SPACE(1),10)
+ CAST(CC as VARCHAR(100))
+ CHAR(10)
+ REPLICATE(SPACE(1),15)
+ Descr
+ CHAR(10)
+ REPLICATE(SPACE(1),10)
+ C_NO
+ CHAR(10)
+ REPLICATE(SPACE(1),15)
+ Vol_Wt
FROM CTE5
In Text Mode(CTRL + T), the result is
2050
Des1
123
20
40
125
20
40
126
20
40
2060
Des2
123
30
50
125
30
50
And in Grid Mode(CTRL + D) , the result is
(No column name)
2050
Des1
123
20
40
125
20
40
126
20
40
2060
Des2
123
30
50
125
30
50
However, SQL Server (or any database) is not the place to do formatting as others spoke about.Please look into the matter.
I wouldn't do this. TSQL is used to get the data, then you format that data with application code.
But if you're working in Query analyzer and just want the output there, you can try the following:
DECLARE mytable_cursor CURSOR FOR
SELECT CC, Descr, C_NO, Vol, Wt
FROM myTable
ORDER BY CC, Descr, C_NO
OPEN mytable_cursor;
FETCH NEXT FROM mytable_cursor
INTO #CC, #Descr, #C_NO, #Vol, #Wt
SET #oCC = #CC
SET #oDescr = #Descr
SET #oC_NO = #C_NO
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #CC;
WHILE ##FETCH_STATUS = 0 AND #oCC = #CC
BEGIN
PRINT ' ' + #Descr;
WHILE ##FETCH_STATUS = 0 AND #oDescr = #Descr
BEGIN
PRINT ' ' + #C_NO;
WHILE ##FETCH_STATUS = 0 AND #oC_NO = #C_NO
BEGIN
PRINT ' ' + #Vol;
PRINT ' ' + #WT;
FETCH NEXT FROM mytable_cursor
INTO #CC, #Descr, #C_NO, #Vol, #Wt
END
SET #oC_NO = #C_NO
END
SET #oDescr = #Descr
END
SET #oCC = #CC
END
CLOSE mytable_cursor;
DEALLOCATE mytable_cursor;
Or you can use a GROUP BY ... WITH ROLLUP and CASE WHEN to get the results a single query.
Here's an example with dashes instead of spaces to make sure the formatting is visible:
SELECT (CASE
WHEN Descr IS NULL THEN CC
WHEN C_NO IS NULL THEN '----' + Descr
WHEN Vol IS NULL THEN '--' + C_NO
WHEN Wt IS NULL THEN '------' + Vol
ELSE '------' + Wt
END)
FROM
(SELECT CC, Descr, C_NO, Vol, Wt
FROM my
GROUP BY CC, Descr, C_NO, Vol, Wt
WITH ROLLUP) AS x
WHERE CC IS NOT NULL
ORDER BY CC, Descr, C_NO, Vol, Wt
You can't do this in tsql code. You need to do this sort of thing in the application code.
One of the best way to represent data in hierarchical order is using XML. Something more, often the use of XML is connected with great performance.
Using your example information and this peace of code:
;WITH DistinctValues (CC,Descr ) AS
(
SELECT DISTINCT CC,Descr
FROM #TableOne
)
SELECT (
SELECT CC AS "CC/#CC"
,Descr AS "CC/Descr"
,(
SELECT C_NO AS "C_NO/#C_NO",
Vol AS "C_NO/Vol",
Wt AS "C_NO/Wt"
FROM #TableOne AS Data
WHERE Data.CC=DV.CC AND Data.Descr=DV.Descr
FOR XML PATH(''),TYPE
) AS "CC"
FROM DistinctValues AS DV
FOR XML PATH(''),TYPE
)
FOR XML PATH('Source'),TYPE
I get the following result (in the form of one row return by the statement above):
<Source>
<CC CC="2050">
<Descr>Des1</Descr>
<C_NO C_NO="123">
<Vol>20</Vol>
<Wt>40</Wt>
</C_NO>
<C_NO C_NO="125">
<Vol>20</Vol>
<Wt>40</Wt>
</C_NO>
<C_NO C_NO="126">
<Vol>20</Vol>
<Wt>40</Wt>
</C_NO>
</CC>
<CC CC="2060">
<Descr>Des2</Descr>
<C_NO C_NO="123">
<Vol>30</Vol>
<Wt>50</Wt>
</C_NO>
<C_NO C_NO="125">
<Vol>30</Vol>
<Wt>50</Wt>
</C_NO>
</CC>
</Source>
Note that the XML functions in T-SQL combined with the XML language structure gives you a huge of possible variations of output data formats - you use one or many nodes, you can represent the the data as attributes or node text. Combine this as you like and as you feel it will be easiest to work with in your application level.
Here is the whole code (just copy and paste) that I have used to generated the previous XML structure:
DECLARE #TableOne TABLE
(
CC BIGINT,
Descr NVARCHAR(10),
C_NO INT,
Vol SMALLINT,
WT SMALLINT
)
INSERT INTO #TableOne(CC,Descr,C_NO,Vol,WT)
VALUES (2050,'Des1',123,20,40)
,(2060,'Des2',123,30,50)
,(2050,'Des1',125,20,40)
,(2060,'Des2',125,30,50)
,(2050,'Des1',126,20,40)
;WITH DistinctValues (CC,Descr ) AS
(
SELECT DISTINCT CC,Descr
FROM #TableOne
)
SELECT (
SELECT CC AS "CC/#CC"
,Descr AS "CC/Descr"
,(
SELECT C_NO AS "C_NO/#C_NO",
Vol AS "C_NO/Vol",
Wt AS "C_NO/Wt"
FROM #TableOne AS Data
WHERE Data.CC=DV.CC AND Data.Descr=DV.Descr
FOR XML PATH(''),TYPE
) AS "CC"
FROM DistinctValues AS DV
FOR XML PATH(''),TYPE
)
FOR XML PATH('Source'),TYPE
This works like a charm and it is tested on Microsoft SQL Server Management Studio 2012.