SQL Pivot - take a changing date from column and make it a row header - sql

I have a basic query that looks like this.
SELECT Database_Name,
FilingDate,
SUM(ISNULL([column1], 0) + ISNULL(column2], 0) +
ISNULL([column3], 0) + ISNULL([column4], 0)) AS Total
FROM SomeTable(NOLOCK)
GROUP BY Database_Name,
FilingDate
ORDER BY Database_Name,
FilingDate DESC
This query outputs results that look like this.
I would like to take the dates returned in the FilingDate column and use them as new column headers with the totals for each database and date being used as the row content. The end result should look like this:
My research suggests that a pivot is the best option but I'm struggling to find the right way to execute it as my dates change each day Any assistance would be appreciated.

If this is MS SQL, you can use a dynamic pivot table. Here is a solution using your query (should work, but I don't have the base data to test it).
SELECT Database_Name,
FilingDate,
SUM( ISNULL(column1 ,0) +
ISNULL(column2],0) +
ISNULL([column3],0) +
ISNULL([column4],0)
) AS Total
INTO #T1
FROM SomeTable(NOLOCK)
GROUP BY Database_Name,
FilingDate
DECLARE #PivotColumnHeaders varchar(MAX)
SELECT #PivotColumnHeaders =
COALESCE(
#PivotColumnHeaders + ',[' + CAST(UC.FilingDate AS NVARCHAR(10)) + ']',
'[' + CAST(UC.FilingDate AS NVARCHAR(10)) + ']'
)
FROM (SELECT FilingDate FROM #T1 GROUP BY FilingDate) UC
DECLARE #PQuery varchar(MAX) = '
SELECT * FROM (SELECT Database_Name, FilingDate, Total FROM #T1 T0) T1
PIVOT (SUM([Total]) FOR FilingDate IN (' + #PivotColumnHeaders + ') ) AS P'
EXECUTE (#PQuery)
DROP TABLE #T1

Related

How to get columns with specific string

I am working in SQL Server 2014 and below is my database with which I am working on and need some analysis done on it.
Upon inspecting the database sample carefully we can notice a number 8777 in L9 and in L13 column.
Now I want to get only those columns which have 8777 in them and in the end a column named "count" which shows how many times the number appeared means I need in output something like this as shown below:
So far I have written this query which is giving the category and subcategory correct. But it is showing all the columns. I have no idea how to count the occurrences of a number and show its count in a count column.
select *
from Sheet2$
where '8777' IN ([L1],[L2],[L3],[L4],[L5],[L6],[L7],[L8],[L9],[L10],[L11],[L12],[L13]
To dynamically limit the columns, you would need Dynamic SQL
Example
Select *
Into #Temp
From YourTable A
Unpivot ( Value for Item in ([L1], [L2],[ L3], [L4], [L5], [L6], [L7], [L8], [L9], [L10], [L11], [L12], [L13]) ) u
Where Value = 8777
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(Item) From #Temp Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Select *,[Count] = sum(1) over()
From #Temp A
Pivot (max(Value) For [Item] in (' + #SQL + ') ) p'
Exec(#SQL);
Returns
Category SubCategory L13 L9 Count
C1 SC1 NULL 8777 2
C1 SC3 8777 NULL 2
Hmmm. I think you want the original rows with the count. I think this is:
declare #cols nvarchar(max);
declare #sql nvarchar(max);
set #cols = (select distinct ', ' + v.colname
from t cross apply
(values ('l1', l1),
('l2', l2),
('l3', l3),
('l4', l4),
('l5', l5),
('l6', l6),
('l7', l7),
('l8', l8),
('l9', l9),
('l10', l10),
('l11', l11),
('l12', l12),
('l13', l13)
) v(colname, val)
where v.val = '8777'
for xml path ('')
);
set #sql = '
select category, subcategory' + #cols + ',
count(*) over () as cnt
from t
';
exec sp_executesql #sql;
The only difference from your result is that the count is on every row. That can easily be adjusted using a case expression, but I'm not sure it is necessary.
If you want the count in only one row, then:
set #sql = '
select category, subcategory' + #cols + ',
(case when row_number() over (order by category, subcategory) = 1
then count(*) over ()
end) as cnt
from t
order by category, subcategory
';
You can try this part as a replacement of John's answer's second query to get the proper count, it does not achieve the exact thing you want but can be a work around.
Declare #sql varchar(max) = Stuff((Select Distinct ',' + QuoteName(Item)
From #Temp Order by 1 For XML Path('')),1,1,'')
print #sql;
Select #SQL = '
Select *,value=8777
From #Temp A
Pivot (Count(Value) For [Item] in (' + #sql + ') ) p'
print #sql;
Exec(#SQL);
I just used count function in pivot in place of sum.

SQL Server - PIVOT using variable

I'm trying to do a pivot in SQL Server using a column with a lot of levels. Currently I'm doing a
select '[' + category_1 + '],', count(*)
from myTable
group by '[' + category_1 + '],'
and copying and pasting the output into the text editor.
I was wondering if it's possible to declare a variable and use that as the IN ([],[],[]) information in the pivot command. Has anyone been able to do that?
I think it would look something like this:
#factorLevels = (select '[' + category_1 + '],' from (select category_1, count(*) from myTable) t1)
SELECT *
FROM
(select category_1, item_count from myTable) as t1
PIVOT
(
SUM(item_count)
FOR category_1 IN (#factorLevels)
) as PivotTable;
If I'm understanding you correctly, I think I have a solution. You can use dynamic SQL for this.
You will need to set a variable that contains all the values for the field by which you want to pivot, and then assign the query itself into a variable and execute it to get results:
DECLARE
#values VARCHAR(50),
#querytext VARCHAR(MAX)
;
SET #values = (SELECT '('+(SELECT STUFF(( SELECT ',[' + category_1 +']' FROM
<your table> FOR XML PATH('')), 1, 1, '') )+')')
;
SELECT #querytext =
'SELECT *
FROM (
SELECT
<your fields>
FROM
<your table>
WHERE
<your criteria>
GROUP BY
<your grouping>
) AS Main
PIVOT (
SUM(item_count)
FOR [category_1] IN ' + #values + '
) AS PivotSum'
EXEC sp_executesql #querytext

Adding ISNULL into a small dynamic header script

We are using this small recursive script to create a string for the dynamic headers of a table - the variable feeds into a piece of dynamic sql.
DROP TABLE IF EXISTS #PivotStep1;
CREATE TABLE #PivotStep1(PlayMonth VARCHAR(25))
INSERT INTO #PivotStep1
values
('01-oct-2016'),
('01-nov-2016'),
('01-dec-2016'),
('01-jan-2017'),
('01-feb-2017');
DECLARE #ColumnName AS nvarchar(MAX)
SELECT #ColumnName = ISNULL(#ColumnName + ',','')
+ QUOTENAME(PlayMonth)
FROM (
SELECT DISTINCT PlayMonth
FROM #PivotStep1
) AS ps
SELECT #ColumnName;
The above gives the following:
[01-dec-2016],[01-feb-2017],[01-jan-2017],[01-nov-2016],[01-oct-2016]
What we want is to surround each column name with ISNULL and AS... So the desired output is the following:
ISNULL([01-dec-2016],0) AS [01-dec-2016],ISNULL([01-feb-2017],0) AS [01-feb-2017],ISNULL([01-jan-2017],0) AS [01-jan-2017],ISNULL([01-nov-2016],0) AS [01-nov-2016],ISNULL([01-oct-2016],0) AS [01-oct-2016]
We would like to keep using the above recursive approach rather than using STUFF and XML.
Use the quotename twice and do other required concatenation.
Try this:
select #ColumnName = ISNULL(#ColumnName + ',', '')
+ 'ISNULL(' + QUOTENAME(PlayMonth) + ', 0) as ' + QUOTENAME(PlayMonth)
from (
select distinct PlayMonth
from #PivotStep1
) as ps
select #ColumnName;
Demo

How to convert string of numbers ( '14, 72' ) to numbers in sql query

declare #lkaklf as varchar(Max)
Select ss.Data from SplitString('14,72', ',') as ss
Select #lkaklf = CONVERT(varchar, COALESCE( + #lkaklf + ',', '') + '''' + Data + '''') From
(
Select Data from SplitString('14,72', ',')
)de
select #lkaklf
print #lkaklf
Select * from LPO Where CONVERT(varchar, LPO.LocalPurchaseOrderId) in (#lkaklf)
#lkalf value is Printing in message but not coming into select query... Why ?
You cannot do what you want. I would recommend that you skip over the splitting part of the query and just do:
where ','+#lkaklf+',' like ','+cast(LPO.LocalPurchaseOrderId as varchar(255))+',%'
That is, just use string comparisons.
If you really want to use SplitString(), then put the results in a temporary table:
insert into #t
select data from splitstring('14,72', ',')
And then use a subquery:
where cast(#lkalklf as varchar(255)) in (select data from #t)

How can I create a month name as a column name for a given date range in sql?

I have a data as below:
Table
country date value
------------------------------------------------------
test1 5/1/2008 500
test1 5/7/2008 200
test1 5/8/2008 300
test1 7/1/2008 100
test1 7/2/2008 100
test2 6/1/2008 100
And I want a result as below:
Result
-----------
countryName May-08 Jun-08 July-08
test1 1000 - 200
test2 - 100
This is adapted from T-SQL Pivot? Possibility of creating table columns from row values
You can see it working here: http://sqlfiddle.com/#!3/7b8c0/28
I think you might need to fiddle around with the column ordering
-- Static PIVOT
SELECT *
FROM (SELECT country,
CONVERT(char(3), date, 0) + '-' +
RIGHT(CONVERT(varchar, YEAR(date)), 2) AS date,
value
FROM country) AS D
PIVOT(SUM(value) FOR date IN([May-08],[Jun-08],[Jul-08])) AS P;
GO
-- Dynamic PIVOT
DECLARE #T AS TABLE(y INT NOT NULL PRIMARY KEY);
DECLARE
#cols AS NVARCHAR(MAX),
#y AS INT,
#sql AS NVARCHAR(MAX)
SELECT #cols = STUFF(
(SELECT N',' + QUOTENAME(y) AS [text()]
FROM (SELECT DISTINCT CONVERT(char(3), date, 0) + '-' +
RIGHT(CONVERT(varchar, YEAR(date)), 2) AS y
FROM Country
) AS Y
ORDER BY y desc
FOR XML PATH('')),
1, 1, N'')
-- Construct the full T-SQL statement
-- and execute dynamically
SET #sql = N'SELECT *
FROM (SELECT country, CONVERT(char(3), date, 0) + ''-'' +
RIGHT(CONVERT(varchar, YEAR(date)), 2) AS date, value
FROM Country) AS D
PIVOT(SUM(value) FOR date IN(' + #cols + N')) AS P;'
EXEC sp_executesql #sql
You have to use a rather complex query for that, using a LOOP it think.
For creating dynamic column names look at this post: https://stackoverflow.com/a/10926106/1321564
With sql server you have some advantages: https://stackoverflow.com/a/5638042/1321564