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;
Related
I have this query that runs regularly.
SELECT REPLICATE('0', 10-LEN(PolicyNumber)) + PolicyNumber AS PolicyNumber,
REPLICATE('0', 7-LEN(BOCBranch)) + BOCBranch AS BOCBranch,
CIFNumber+ REPLICATE(' ', 8-LEN(CIFNumber)) AS CIFNumber,
REPLICATE('0', 7-LEN(EmployeeNumber)) + EmployeeNumber AS EmployeeNumber,
PremiumSign,
REPLACE(REPLICATE('0',16-LEN(CAST(Premium AS VARCHAR))) + CAST(Premium AS VARCHAR),'.','') AS Premium,
CASE WHEN RegistrationDate IS NULL
THEN REPLICATE(' ', 8)
ELSE REPLACE(CONVERT(VARCHAR(10),RegistrationDate,103),'/','')
END AS RegistrationDate,
ActivityCode + REPLICATE(' ', 10-LEN(ActivityCode)) AS ActivityCode,
ActivityDescription + REPLICATE(' ', 255-LEN(ActivityDescription)) AS ActivityDescription,
PolicyTypeCode + REPLICATE(' ', 10-LEN(PolicyTypeCode)) AS PolicyTypeCode,
PolicyTypeDescription + REPLICATE(' ', 255-LEN(PolicyTypeDescription)) AS PolicyTypeDescription,
ContributionCode + REPLICATE(' ', 10-LEN(ContributionCode)) AS ContributionCode,
ContributionDescription + REPLICATE(' ', 255-LEN(ContributionDescription)) AS ContributionDescription,
ActivityMilimetra + REPLICATE(' ', 1-LEN(ActivityMilimetra)) AS ActivityMilimetra,
REPLICATE('0', 8-LEN(SourceCode)) + CAST(SourceCode AS varCHAR) AS SourceCode
FROM FileExtraction.EXTR_MILIMETRA
ORDER BY PolicyNumber
I have created a new table called FIELD_ACTIVATIONS as per managerial instructions like so:
FieldName CategoryID IsActive
-------------------------------------------------- ----------- --------
PolicyNumber 1 1
BOCBranch 1 1
CIFNumber 1 1
EmployeeNumber 1 0
PremiumSign 1 0
RegistrationDate 1 0
ActivityCode 1 0
ActivityDescription 1 0
PolicyTypeCode 1 0
PolicyTypeDescription 1 0
ContributionCode 1 0
ContributionDescription 1 0
ActivityMilimetra 1 0
SourceCode 1 0
Premium 1 0
PolicyNumber 2 0
BOCBranch 2 0
CIFNumber 2 0
EmployeeNumber 2 1
PremiumSign 2 1
RegistrationDate 2 1
ActivityCode 2 0
ActivityDescription 2 0
PolicyTypeCode 2 0
PolicyTypeDescription 2 0
ContributionCode 2 0
ContributionDescription 2 0
ActivityMilimetra 2 0
SourceCode 2 0
Premium 2 0
PolicyNumber 3 0
BOCBranch 3 0
CIFNumber 3 0
EmployeeNumber 3 0
PremiumSign 3 0
RegistrationDate 3 0
ActivityCode 3 1
ActivityDescription 3 1
PolicyTypeCode 3 1
PolicyTypeDescription 3 0
ContributionCode 3 0
ContributionDescription 3 0
ActivityMilimetra 3 0
SourceCode 3 0
Premium 3 0
PolicyNumber 4 0
BOCBranch 4 0
CIFNumber 4 0
EmployeeNumber 4 0
PremiumSign 4 0
RegistrationDate 4 0
ActivityCode 4 0
ActivityDescription 4 0
PolicyTypeCode 4 0
PolicyTypeDescription 4 1
ContributionCode 4 1
ContributionDescription 4 1
ActivityMilimetra 4 1
SourceCode 4 1
Premium 4 1
As you may notice, each column in the SELECT statement, is a FieldName in the table.
What I need to do is to run that SELECT statement only for the columns that appear in FieldName that have a status of IsActive = 1. For the columns in the SELECT query that have a status of IsActive = 0, I would still like to select the column, but display it as an empty column.
This is all without permanently deleting or altering anything from any tables.
I've tried using Cases, Subqueries, IFs and I cannot seem to come up with a solution that will not require future alteration if any details in the FIELD_ACTIVATIONS table change.
I've also looked at this link Select records in on table based on conditions from another table? but this link presumes that there is a common field in both tables.
The main table named as "EXTR_MILIMETRA" displayed in the SELECT query has nothing in common with FIELD_ACTIVATION apart from the column name and the field name.
Here is a sample of the columns in "EXTR_MILIMETRA". (Not all columns are being shown because of limited screen space.) Each column show below is a FieldName is the table above.
By asking this I'm risking being blocked due to consecutive previous downvotes. If any extra information is needed please let me know first instead of downvoting. If that's ok. I've really tried to describe my problem well enough.
Happy to make any clarifications.
How you would write that depends on if you need performance or not. If you don't have too many rows then you can do it like:
WITH active AS
(
SELECT FieldName
FROM Field_Activations
WHERE CategoryId=1 AND IsActive=1
)
SELECT
CASE WHEN EXISTS (SELECT * FROM active WHERE FieldName='PolicyNumber')
THEN REPLICATE('0', 10-LEN(PolicyNumber)) + PolicyNumber
ELSE '' END AS PolicyNumber,
CASE WHEN EXISTS (SELECT * FROM active WHERE FieldName='BOCBranch')
then REPLICATE('0', 7-LEN(BOCBranch)) + BOCBranch
ELSE '' end AS BOCBranch,
--...
FROM FileExtraction.EXTR_MILIMETRA
ORDER BY PolicyNumber;
If you need some performance then you can write the above query as a dynamic query with a series of if and execute:
DECLARE #SQLString nvarchar(4000);
declare #active table (FieldName varchar(100));
insert into #active (FieldName)
SELECT FieldName
FROM Field_Activations
WHERE CategoryId=1 AND IsActive=1;
SET #SQLString = N'
SELECT ' +
CASE when EXISTS
(SELECT * FROM #active WHERE FieldName = 'PolicyNumber')
THEN 'REPLICATE(''0'', 10-LEN(PolicyNumber)) + PolicyNumber'
ELSE '''''' END + ' AS PolicyNumber,' +
CASE WHEN EXISTS
(SELECT * FROM #active WHERE FieldName = 'BOCBranch')
THEN 'REPLICATE(''0'', 7-LEN(BOCBranch)) + BOCBranch'
ELSE '''''' end + ' AS BOCBranch,' +
--... +
' FROM FileExtraction.EXTR_MILIMETRA
ORDER BY PolicyNumber;'
print #SQLString
EXECUTE sp_executesql #SQLString;
#NikosV you need is a dynamic query. I have called it #DynamicQuery and a method to assign those columns that you are intersted in hiding will have NULL added to them, rendering their output to be blanks. Have a look at this mock up, just change the TABLENAME to the actual name of the table you want to pull the data from and use the actual FIELD_ACTIVATIONS table you said you creatd.
DECLARE #FIELD_ACTIVATIONS TABLE (FieldName varchar(200), CategoryID int, IsActive bit)
INSERT INTO #FIELD_ACTIVATIONS
SELECT 'PolicyNumber', 1, 1 UNION ALL
SELECT 'BOCBranch', 1, 1 UNION ALL
SELECT 'CIFNumber', 1, 1 UNION ALL
SELECT 'EmployeeNumber', 1, 0 UNION ALL
SELECT 'PremiumSign', 1, 0 UNION ALL
SELECT 'RegistrationDate', 1, 0 UNION ALL
SELECT 'ActivityCode', 1, 0 UNION ALL
SELECT 'ActivityDescription', 1, 0 UNION ALL
SELECT 'PolicyTypeCode', 1, 0 UNION ALL
SELECT 'PolicyTypeDescription', 1, 0 UNION ALL
SELECT 'ContributionCode', 1, 0
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += FieldName+','
FROM (SELECT p.FieldName+''+CASE WHEN IsActive=0 THEN '=NULL' ELSE '' END FieldName
FROM #FIELD_ACTIVATIONS p
) AS x;
DECLARE #Querycolumns VARCHAR(MAX)=(select left (#columns, Len ( #columns) - 1 ))
DECLARE #Dynamicquery NVARCHAR(MAX) = '
SELECT '+ #Querycolumns +'
FROM
TABLENAME
'
The output query will be run like this :
SELECT PolicyNumber,BOCBranch,CIFNumber,EmployeeNumber=NULL,PremiumSign=NULL,RegistrationDate=NULL,ActivityCode=NULL,ActivityDescription=NULL,PolicyTypeCode=NULL,PolicyTypeDescription=NULL,ContributionCode=NULL
FROM
TABLENAME
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
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))
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.
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)