What is the SQL code for aggregating values? - sql

I have the following table:
GR WORD NO.
1 A 4
2 B 5
3 C 6
1 G 5
2 H 5
3 I 5
I would like to get the following table:
GR 4 5 6
1 1 1 0
2 0 2 0
3 0 1 1
For each GR column value I count the NO. values.

Here's a dynamic solution:
--Sample data
--CREATE TABLE tbl (GR int, WORD char(1), [NO] int)
--INSERT INTO tbl values
--(1,'A',4),
--(2,'B',5),
--(3,'C',6),
--(1,'G',5),
--(2,'H',5),
--(3,'I',5)
DECLARE #sql NVARCHAR(MAX)
SELECT #sql = '
SELECT *
FROM tbl
PIVOT(
COUNT(WORD) FOR [NO] IN (' +
(SELECT STUFF(
(
SELECT DISTINCT ',' + QUOTENAME(CAST([NO] AS VARCHAR(10)))
FROM tbl
FOR XML PATH('')
)
, 1, 1, ''))
+ ')
) p
'
EXEC sp_executesql #sql

This is a conditional aggregation
select
GR
,[4] = count(case when NO. = 4 then WORD end)
,[5] = count(case when NO. = 5 then WORD end)
,[6] = count(case when NO. = 6 then WORD end)
from YourTable
group by GR
Or a pivot
select *
from YourTable
pivot(
count(WORD) for NO. in ([4],[5],[6])
) p

Related

How to create columns from a list of values

I have the following data:
Table 1
Row ID Value Cost
1 1 Priority 1 10,000
2 2 Priority 2 9,000
3 3 Priority 3 8,000
4 4 Priority 4 6,000
Table 2
Row Name Priority Cost
1 Jon 1 10,000
2 Bob 3 8,000
3 Dan 4 7,000
4 Steve 2 9,000
5 Bill 3 8,000
...
I want the table to look like this:
Table 3
Row Name Priotity 1 Priority 2 Priority 3 Priority 4
1 Jon 10,000
2 Bob 8,000
3 Dan 7,000
4 Steve 9,000
5 Bill 8,000
...
How can I create rows from Table 1 as columns, and fill in the output as shown in Table 3.
I am hoping this is not as basic as it sounds, but my SQL is terrible!
you can try this for dynamic pivot table.
DECLARE #columns VARCHAR(8000)
SELECT #columns = COALESCE(#columns + ',[' + cast(Value as varchar) + ']',
'[' + cast(Value as varchar)+ ']')
FROM Table1
GROUP BY Value
DECLARE #query VARCHAR(8000)
SET #query = 'with Priorites as
(select a.Name,b.Value,b.Cost from Table2 a left join Table1 b on a.Priority =b.id)
SELECT *
FROM Priorites
PIVOT
(
MAX(Cost)
FOR [Value]
IN (' + #columns + ')
)
AS p'
EXECUTE(#query)
Here is the link for more details http://www.tsqltutorials.com/pivot.php
Pivot is always useful in this sort of scenario, but if the actual data is as simple as it's in question (like there are only 4 unique Priority and/or only 1 Priority is assigned to a particular user),then you can achieve this task with following query:
select t.row,t.name
(case when t.priority = 1 then t.cost
else ' '
end
) as Priority1,
(case when t.priority = 2 then t.cost
else ' '
end
) as Priority2,
(case when t.priority = 3 then t.cost
else ' '
end
) as Priority3,
(case when t.priority = 4 then t.cost
else ' '
end
) as Priority4
From
(select Row,name,priority,cost
from Table2
group by name) t
group by t.name;

How to use SQL Server 2005 Pivot based on lookup table

table [Status] has the following data:
ID Status
1 PaymentPending
2 Pending
3 Paid
4 Cancelled
5 Error
====================================
Data Table has the following structure:
ID WeekNumber StatusID
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 2 2
7 2 3
Looking for a Pivot
Week # PaymentPending Pending Paid Cancelled
Week 1 1 1 1 0
Week 2 1 2 1 0
SELECT 'Week '+CAST(coun.WeekNumber AS VARCHAR(10)) [Week #],[PaymentPending],[Pending],[Paid],[Cancelled],[Error] FROM
(SELECT [WeekNumber],[Status] FROM dbo.WeekDetails
INNER JOIN [dbo].[Status] AS s
ON [dbo].[WeekDetails].[StatusID] = [s].[ID]) AS wee
PIVOT (COUNT(wee.[Status]) FOR wee.[Status]
IN ([PaymentPending],[Pending],[Paid],[Cancelled],[Error])) AS Coun
A pivot might look like this:
SELECT * FROM
(SELECT
'Week ' + CAST(D.WeekNumber AS varchar(2)) [Week #],
S.Status
FROM DataTbl D
INNER JOIN Status S ON D.StatusID = S.ID
) Derived
PIVOT
(
COUNT(Status) FOR Status IN
([PaymentPending], [Pending], [Paid], [Cancelled]) -- add [Error] if needed
) Pvt
If you expect the number of items in theStatustable to change you might want to consider using a dynamic pivot to generate the column headings. Something like this:
DECLARE #sql AS NVARCHAR(MAX)
DECLARE #cols AS NVARCHAR(MAX)
SELECT #cols = ISNULL(#cols + ',','') + QUOTENAME(Status)
FROM (SELECT ID, Status FROM Status) AS Statuses ORDER BY ID
SET #sql =
N'SELECT * FROM
(SELECT ''Week '' + CAST(D.WeekNumber AS varchar(2)) [Week #], S.Status
FROM Datatbl D
INNER JOIN Status S ON D.StatusID = S.ID) Q
PIVOT (
COUNT(Status)
FOR Status IN (' + #cols + ')
) AS Pvt'
EXEC sp_executesql #sql;
Sample SQL Fiddle
You can use CASE based aggregation with GROUP BY
SELECT 'Week ' + cast(WeekNumber as varchar(10)) as 'Week#',
SUM ( CASE WHEN StatusId =1 THEN 1 else 0 end) as 'PaymentPending',
SUM ( CASE WHEN StatusId =2 THEN 1 else 0 end) as 'Pending',
SUM ( CASE WHEN StatusId =3 THEN 1 else 0 end) as 'Paid',
SUM ( CASE WHEN StatusId =4 THEN 1 else 0 end) as 'Cancelled'
FROM DataTbl D
GROUP BY 'Week ' + cast(WeekNumber as varchar(10))

Aggregate function within inner select in Pivot query using SQL Server

I have the following table:
select * from product;
slno item
---------------
1 HDD
2 PenDrive
3 RAM
4 DVD
5 RAM
6 HDD
7 RAM
7 RAM
7 RAM
Now I need to do pivoting for this table for which i am using following query:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(item)
from product
group by item
order by item
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT slno,TotalProduct ,' + #cols + '
from
(
select slno,Count(*) as TotalProduct,item
from product
group by slno,item
) x
pivot
(
count(item)
for item in (' + #cols + ')
) p '
exec(#query)
Result:
slno TotalProducts DVD HDD PenDrive RAM
---------------------------------------------
1 1 0 1 0 0
2 1 0 0 1 0
3 1 0 0 0 1
4 1 1 0 0 0
5 1 0 0 0 1
6 1 0 1 0 0
7 3 0 0 0 1
Note The total of product RAM is 3 but in Column RAM showing only 1. I have used COUNT(*) aggregate function within the inner select statement in #query. How can i show actual count?
You only need to group by slno, not by the combination of slno and item. Therefore, you need to change the query which provides a source for your pivot as follows:
set #query = 'SELECT slno,totalproduct,' + #cols + '
from
(
select p.slno slno, c.count as totalproduct, p.item
from product p
inner join
(select slno, count(item) count
from product
group by slno) c on p.slno = c.slno
) x
pivot
(
count(item)
for item in (' + #cols + ')
) p '
Demo
Use following sub query instead of your sub query:
select slno,Count(*) OVER (PARTITION BY slno) as TotalProduct,item
from product
Edit: Count(*) Over(Partition by ...) supported in SQL Server 2012 and above versions.

Generate comma separated value based on input in sql

I have a table called Rule_X_ListType in the following structure
Rue_ID ListType_ID Value
---------------------------
1 2 319
1 2 400
1 5 8150
1 5 1000
1 3 10211
2 2 400
2 6 10211
3 7 10211
3 3 8051
2 2 319
If I will give the input as Rule_ID = 1 and ListType_ID = 2, then I need the output as a string with values :
319,400
Anybody please help out...Thanks in advance...
I do not feel the neccessity for either the CTE or the FOR XML PATH.
This can be accomplished using the much more simple method of COALESCE
DECLARE #List varchar(100)
SELECT
#List = COALESCE(#List + ', ', '') + CAST(Value AS varchar(10))
FROM
Rule_X_ListType
WHERE
Rule_ID = 1 and ListType_ID = 2
SELECT #List
Try this
;WITH CTE AS
(
SELECT * FROM Rule_X_ListType WHERE Rue_ID = 1 AND ListType_ID = 2
)
SELECT STUFF
(
(SELECT ',' + A.Value FROM CTE A ORDER BY A.VALUE FOR XML PATH('')),1,1,''
) AS CSVValues
SELECT DISTINCT T1.Rule_ID,T1.ListType_ID,STUFF(VAL,1,1,'') AS VALUE
FROM Rule_X_ListType T1
CROSS APPLY (SELECT ',' + CONVERT(VARCHAR,Value)
FROM Rule_X_ListType T2
WHERE T1.Rule_ID =T2.Rule_ID and T1.ListType_ID =T2.ListType_ID
FOR XML PATH(''))A(VAL)
WHERE T1.Rule_ID = 1 and T1.ListType_ID = 2
SQL Tips and Tricks in http://sqlbay.blogspot.in/

Pivot with dynamic columns

There are 4 tables:
Suppl, fields: (Code_name, Code_name_arch, Tasknum, Pki_num, Group_eng, Name, Descr, Cost, Quan, shop);
Maker, fields : (Code_maker, Code_maker_arch, Code_name, provider);
Arrival, fields: (Code_arr, Code_maker, quan_arr);
Accounts, fields: (Code_acc, Code_maker, num_acc, quan_acc, summ)
my query is:
ALTER Procedure [dbo].[pr_tblz] As
Set NOCOUNT ON
Declare #task VARCHAR(4000)
Select #task = coalesce(#task + ',[' + [Tasknum] + ']',
'[' + [Tasknum] + ']')
FROM [db_pki].[dbo].[Suppl]
Group BY [Tasknum]
Order BY [Tasknum]
Declare #query VARCHAR(8000)
Set #query='
Alter View Amountzz As
SELECT Shop, Name, Desc, Group_eng as GI, '+ #task +', quan_arr As specif, quan_acc As acns
FROM
(
select
Shop, Name, Desc, Group_eng, Tasknum, Quan, quan_arr, quan_acc
from [db_pki].[dbo].[Suppl] as deliveries
LEFT JOIN [db_pki].[dbo].[Maker] ON (deliveries.[Code_name] = [db_pki].[dbo].[Maker].[Code_name])
LEFT JOIN [db_pki].[dbo].[Arrival] ON ([db_pki].[dbo].[Maker].[Code_maker] = [db_pki].[dbo].[Arrival].[Code_maker])
LEFT JOIN [db_pki].[dbo].[Accounts] ON ([db_pki].[dbo].[Maker].[Code_maker] = [db_pki].[dbo].[Accounts].[Code_maker])
)date_to_pivot
PIVOT
(
Max([Quan])
For [Tasknum]
IN (' + #task + ')
)AS p'
Execute (#query)
result:
Shop Name Descr GI n1 n2 n3 ... specif acns
1 name1 1 5 4 1 1
2 10 name2 2 3 8 2 2
3 name3 3 501 11 3 3
1 8 name1 1 5 16 7 10
a 2 10 name2 2 3 3 5 6
5 name1 1 2 5 6 3
How can I get the following result?
Shop Name Descr GI n1 n2 n3 ... specif acns
1 8 name1 1 5 4 16 8(1+7) 11
a 2 10 name2 2 3 8 3 7 8(2+6)
3 name3 3 501 11 3 3
5 name1 1 2 5 6 3
n1, n2, n3,... - Tasknum
Not tested. Try aggregating the values of Shop, specif and acns in the subselect that pulls the columns before the pivoting, like this (the necessary changes are highlighted in bold):
ALTER Procedure [dbo].[pr_tblz] As
Set NOCOUNT ON
Declare #task VARCHAR(4000)
Select #task = coalesce(#task + ',[' + [Tasknum] + ']',
'[' + [Tasknum] + ']')
FROM [db_pki].[dbo].[Suppl]
Group BY [Tasknum]
Order BY [Tasknum]
Declare #query VARCHAR(8000)
Set #query='
Alter View Amountzz As
SELECT Shop, Name, Desc, Group_eng as GI, '+ #task +', quan_arr As specif, quan_acc As acns
FROM
(
select
MAX(Shop ) OVER (PARTITION BY Name) AS Shop,
Name, Desc, Group_eng, Tasknum, Quan,
SUM(quan_arr) OVER (PARTITION BY Name) AS quan_arr,
SUM(quan_acc) OVER (PARTITION BY Name) AS quan_acc
from [db_pki].[dbo].[Suppl] as deliveries
LEFT JOIN [db_pki].[dbo].[Maker] ON (deliveries.[Code_name] = [db_pki].[dbo].[Maker].[Code_name])
LEFT JOIN [db_pki].[dbo].[Arrival] ON ([db_pki].[dbo].[Maker].[Code_maker] = [db_pki].[dbo].[Arrival].[Code_maker])
LEFT JOIN [db_pki].[dbo].[Accounts] ON ([db_pki].[dbo].[Maker].[Code_maker] = [db_pki].[dbo].[Accounts].[Code_maker])
)date_to_pivot
PIVOT
(
Max([Quan])
For [Tasknum]
IN (' + #task + ')
)AS p'
Execute (#query)