Pivoting on temptable data using sql server [duplicate] - html

I have read the stuff on MS pivot tables and I am still having problems getting this correct.
I have a temp table that is being created, we will say that column 1 is a Store number, and column 2 is a week number and lastly column 3 is a total of some type. Also the Week numbers are dynamic, the store numbers are static.
Store Week xCount
------- ---- ------
102 1 96
101 1 138
105 1 37
109 1 59
101 2 282
102 2 212
105 2 78
109 2 97
105 3 60
102 3 123
101 3 220
109 3 87
I would like it to come out as a pivot table, like this:
Store 1 2 3 4 5 6....
-----
101 138 282 220
102 96 212 123
105 37
109
Store numbers down the side and weeks across the top.

If you are using SQL Server 2005+, then you can use the PIVOT function to transform the data from rows into columns.
It sounds like you will need to use dynamic sql if the weeks are unknown but it is easier to see the correct code using a hard-coded version initially.
First up, here are some quick table definitions and data for use:
CREATE TABLE yt
(
[Store] int,
[Week] int,
[xCount] int
);
INSERT INTO yt
(
[Store],
[Week], [xCount]
)
VALUES
(102, 1, 96),
(101, 1, 138),
(105, 1, 37),
(109, 1, 59),
(101, 2, 282),
(102, 2, 212),
(105, 2, 78),
(109, 2, 97),
(105, 3, 60),
(102, 3, 123),
(101, 3, 220),
(109, 3, 87);
If your values are known, then you will hard-code the query:
select *
from
(
select store, week, xCount
from yt
) src
pivot
(
sum(xcount)
for week in ([1], [2], [3])
) piv;
See SQL Demo
Then if you need to generate the week number dynamically, your code will be:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(Week)
from yt
group by Week
order by Week
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT store,' + #cols + ' from
(
select store, week, xCount
from yt
) x
pivot
(
sum(xCount)
for week in (' + #cols + ')
) p '
execute(#query);
See SQL Demo.
The dynamic version, generates the list of week numbers that should be converted to columns. Both give the same result:
| STORE | 1 | 2 | 3 |
---------------------------
| 101 | 138 | 282 | 220 |
| 102 | 96 | 212 | 123 |
| 105 | 37 | 78 | 60 |
| 109 | 59 | 97 | 87 |

This is for dynamic # of weeks.
Full example here:SQL Dynamic Pivot
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column
SELECT #ColumnName= ISNULL(#ColumnName + ',','') + QUOTENAME(Week)
FROM (SELECT DISTINCT Week FROM #StoreSales) AS Weeks
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery =
N'SELECT Store, ' + #ColumnName + '
FROM #StoreSales
PIVOT(SUM(xCount)
FOR Week IN (' + #ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql #DynamicPivotQuery

I've achieved the same thing before by using subqueries. So if your original table was called StoreCountsByWeek, and you had a separate table that listed the Store IDs, then it would look like this:
SELECT StoreID,
Week1=(SELECT ISNULL(SUM(xCount),0) FROM StoreCountsByWeek WHERE StoreCountsByWeek.StoreID=Store.StoreID AND Week=1),
Week2=(SELECT ISNULL(SUM(xCount),0) FROM StoreCountsByWeek WHERE StoreCountsByWeek.StoreID=Store.StoreID AND Week=2),
Week3=(SELECT ISNULL(SUM(xCount),0) FROM StoreCountsByWeek WHERE StoreCountsByWeek.StoreID=Store.StoreID AND Week=3)
FROM Store
ORDER BY StoreID
One advantage to this method is that the syntax is more clear and it makes it easier to join to other tables to pull other fields into the results too.
My anecdotal results are that running this query over a couple of thousand rows completed in less than one second, and I actually had 7 subqueries. But as noted in the comments, it is more computationally expensive to do it this way, so be careful about using this method if you expect it to run on large amounts of data .

This is what you can do:
SELECT *
FROM yourTable
PIVOT (MAX(xCount)
FOR Week in ([1],[2],[3],[4],[5],[6],[7])) AS pvt
DEMO

I'm writing an sp that could be useful for this purpose, basically this sp pivot any table and return a new table pivoted or return just the set of data, this is the way to execute it:
Exec dbo.rs_pivot_table #schema=dbo,#table=table_name,#column=column_to_pivot,#agg='sum([column_to_agg]),avg([another_column_to_agg]),',
#sel_cols='column_to_select1,column_to_select2,column_to_select1',#new_table=returned_table_pivoted;
please note that in the parameter #agg the column names must be with '[' and the parameter must end with a comma ','
SP
Create Procedure [dbo].[rs_pivot_table]
#schema sysname=dbo,
#table sysname,
#column sysname,
#agg nvarchar(max),
#sel_cols varchar(max),
#new_table sysname,
#add_to_col_name sysname=null
As
--Exec dbo.rs_pivot_table dbo,##TEMPORAL1,tip_liq,'sum([val_liq]),sum([can_liq]),','cod_emp,cod_con,tip_liq',##TEMPORAL1PVT,'hola';
Begin
Declare #query varchar(max)='';
Declare #aggDet varchar(100);
Declare #opp_agg varchar(5);
Declare #col_agg varchar(100);
Declare #pivot_col sysname;
Declare #query_col_pvt varchar(max)='';
Declare #full_query_pivot varchar(max)='';
Declare #ind_tmpTbl int; --Indicador de tabla temporal 1=tabla temporal global 0=Tabla fisica
Create Table #pvt_column(
pivot_col varchar(100)
);
Declare #column_agg table(
opp_agg varchar(5),
col_agg varchar(100)
);
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(#table) AND type in (N'U'))
Set #ind_tmpTbl=0;
ELSE IF OBJECT_ID('tempdb..'+ltrim(rtrim(#table))) IS NOT NULL
Set #ind_tmpTbl=1;
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(#new_table) AND type in (N'U')) OR
OBJECT_ID('tempdb..'+ltrim(rtrim(#new_table))) IS NOT NULL
Begin
Set #query='DROP TABLE '+#new_table+'';
Exec (#query);
End;
Select #query='Select distinct '+#column+' From '+(case when #ind_tmpTbl=1 then 'tempdb.' else '' end)+#schema+'.'+#table+' where '+#column+' is not null;';
Print #query;
Insert into #pvt_column(pivot_col)
Exec (#query)
While charindex(',',#agg,1)>0
Begin
Select #aggDet=Substring(#agg,1,charindex(',',#agg,1)-1);
Insert Into #column_agg(opp_agg,col_agg)
Values(substring(#aggDet,1,charindex('(',#aggDet,1)-1),ltrim(rtrim(replace(substring(#aggDet,charindex('[',#aggDet,1),charindex(']',#aggDet,1)-4),')',''))));
Set #agg=Substring(#agg,charindex(',',#agg,1)+1,len(#agg))
End
Declare cur_agg cursor read_only forward_only local static for
Select
opp_agg,col_agg
from #column_agg;
Open cur_agg;
Fetch Next From cur_agg
Into #opp_agg,#col_agg;
While ##fetch_status=0
Begin
Declare cur_col cursor read_only forward_only local static for
Select
pivot_col
From #pvt_column;
Open cur_col;
Fetch Next From cur_col
Into #pivot_col;
While ##fetch_status=0
Begin
Select #query_col_pvt='isnull('+#opp_agg+'(case when '+#column+'='+quotename(#pivot_col,char(39))+' then '+#col_agg+
' else null end),0) as ['+lower(Replace(Replace(#opp_agg+'_'+convert(varchar(100),#pivot_col)+'_'+replace(replace(#col_agg,'[',''),']',''),' ',''),'&',''))+
(case when #add_to_col_name is null then space(0) else '_'+isnull(ltrim(rtrim(#add_to_col_name)),'') end)+']'
print #query_col_pvt
Select #full_query_pivot=#full_query_pivot+#query_col_pvt+', '
--print #full_query_pivot
Fetch Next From cur_col
Into #pivot_col;
End
Close cur_col;
Deallocate cur_col;
Fetch Next From cur_agg
Into #opp_agg,#col_agg;
End
Close cur_agg;
Deallocate cur_agg;
Select #full_query_pivot=substring(#full_query_pivot,1,len(#full_query_pivot)-1);
Select #query='Select '+#sel_cols+','+#full_query_pivot+' into '+#new_table+' From '+(case when #ind_tmpTbl=1 then 'tempdb.' else '' end)+
#schema+'.'+#table+' Group by '+#sel_cols+';';
print #query;
Exec (#query);
End;
GO
This is an example of execution:
Exec dbo.rs_pivot_table #schema=dbo,#table=##TEMPORAL1,#column=tip_liq,#agg='sum([val_liq]),avg([can_liq]),',#sel_cols='cod_emp,cod_con,tip_liq',#new_table=##TEMPORAL1PVT;
then Select * From ##TEMPORAL1PVT would return:

Here is a revision of #Tayrn answer above that might help you understand pivoting a little easier:
This may not be the best way to do this, but this is what helped me wrap my head around how to pivot tables.
ID = rows you want to pivot
MY_KEY = the column you are selecting from your original table that contains the column names you want to pivot.
VAL = the value you want returning under each column.
MAX(VAL) => Can be replaced with other aggregiate functions. SUM(VAL), MIN(VAL), ETC...
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(MY_KEY)
from yt
group by MY_KEY
order by MY_KEY ASC
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT ID,' + #cols + ' from
(
select ID, MY_KEY, VAL
from yt
) x
pivot
(
sum(VAL)
for MY_KEY in (' + #cols + ')
) p '
execute(#query);

select * from (select name, ID from Empoyee) Visits
pivot(sum(ID) for name
in ([Emp1],
[Emp2],
[Emp3]
) ) as pivottable;

Just give you some idea how other databases solve this problem. DolphinDB also has built-in support for pivoting and the sql looks much more intuitive and neat. It is as simple as specifying the key column (Store), pivoting column (Week), and the calculated metric (sum(xCount)).
//prepare a 10-million-row table
n=10000000
t=table(rand(100, n) + 1 as Store, rand(54, n) + 1 as Week, rand(100, n) + 1 as xCount)
//use pivot clause to generate a pivoted table pivot_t
pivot_t = select sum(xCount) from t pivot by Store, Week
DolphinDB is a columnar high performance database. The calculation in the demo costs as low as 546 ms on a dell xps laptop (i7 cpu). To get more details, please refer to online DolphinDB manual https://www.dolphindb.com/help/index.html?pivotby.html

Pivot is one of the SQL operator which is used to turn the unique data from one column into multiple column in the output. This is also mean by transforming the rows into columns (rotating table). Let us consider this table,
If I want to filter this data based on the types of product (Speaker, Glass, Headset) by each customer, then use Pivot operator.
Select CustmerName, Speaker, Glass, Headset
from TblCustomer
Pivot
(
Sum(Price) for Product in ([Speaker],[Glass],[Headset])
) as PivotTable

Related

Concat blob data in Sql server 2008

I have a table which contains image datatype in SQL SERVER 2008:
select ID,refID,blobcontent from dbo.Script where RefId=6000
ID refID blobcontent
456 45 0x50232323
987 45 0x54238798
852 45 0x52741985
I want to concat blobcontent in a row and insert into a new table group by refID. (the blob contents are long I just paste a sample).
example outpu:
ID ConcatedBlob
456 0x5023232342387982741985
I know there is no direct concat() in sql server 2008 so I wrote the following query:
DECLARE #GroupDept VARBINARY(max)
SELECT #GroupDept = COALESCE(#GroupDept + ', ', '')+ blobcontent
FROM dbo.Script where RefId=6000
SELECT #GroupDept as 'total'
but get the error:
The data types varbinary(max) and varchar are incompatible in the add operator
Where is my mistake? any help is appreciated.
Try this:
First, create and populate sample table (Please save us this step in your future questions):
DECLARE #Script AS TABLE
(
Id int,
RefId int,
Blobcontent varbinary(max)
);
INSERT INTO #Script (Id, RefId, Blobcontent) VALUES
(456, 45, 0x50232323),
(987, 45, 0x54238798),
(852, 45, 0x52741985);
The query:
DECLARE #blobcontent varbinary(max)
SELECT #blobcontent = COALESCE(#blobcontent, 0x0) + blobcontent
FROM #Script
ORDER BY Id;
SELECT #blobcontent;

Set a Value as a Column Name in SQL Select

Assuming I have a list of values after a select from a table:
DEPARTMENT(Table):
+-----------+---------+-----------+-----------+
| DEPT_NAME | DEPT_ID | DEPT_CITY | DEPT_TYPE |
+-----------+---------+-----------+-----------+
| | | | |
+-----------+---------+-----------+-----------+
Now,
my SELECT Query should be:
SELECT DEPT_NAME,DEPT_ID,DEPT_CITY from LOCATIONS table where (external condition);
i think this can be done using pivot table.
please check this this tutorial http://www.artfulsoftware.com/infotree/queries.php#78
further you can check these in SO itself,
MySQL pivot table
if you're using MS SQL you can use the FOR XML Path('') statement and create dymanic sql query as followed:(I dnn't have access to other SQL Management Systems so I don't know if this would work for them.
DECLARE #columns varchar(255) = (select ',' + [Column] FROM (Values('DEPT_NAME'),('DEPT_ID'),('DEPT_CITY'),('DEPT_TYPE')) as tColumns([column])FOR XML PATH(''))
--select #columns
DECLARE #stmt varchar(255) = 'Select 1 as DummyColumn ' + #columns + ' from LOCATIONS table where (external condition);'
--select #stmt
EXEC(#stmt)
in this case I'm using 255 as the length of the variables; but you can change that to anything of your liking.
(Values('DEPT_NAME'),('DEPT_ID'),('DEPT_CITY'),('DEPT_TYPE')) as tColumns([column]) is an inline values table; you need to replace this with the correct select statement.

In mssql Summing values in a cell with '$$' separated Integers, but data type is varchar

I have below table with Table data
ID |Department | SaleMngrs(VARCHAR(200)) |
---------------------------------------------
1 |Technics | '1$$2$$3$$4'|
2 |Development| '10$$21$$43'|
I want the result as given below
ID |Department | SaleMngrs | sum
-------------------------------------
1 |Technics | '1$$2$$3$$4'| 10
2 |Development| '10$$21$$43'| 74
If you are using SQL server then use Solution number #1 or if you are using MySql then go for solution number #2
Solution #1
For SQL server it would be better to use Function to split the string and get the values from it, you need to Create the Below function
Function SplitStrings
CREATE FUNCTION SplitStrings
(
#Input NVARCHAR(MAX),
#Character CHAR(2)
)
RETURNS #Output TABLE (
Item NVARCHAR(1000)
)
AS
BEGIN
DECLARE #StartIndex INT, #EndIndex INT
SET #StartIndex = 1
IF SUBSTRING(#Input, LEN(#Input) - 1, LEN(#Input)) <> #Character
BEGIN
SET #Input = #Input + #Character
END
WHILE CHARINDEX(#Character, #Input) > 0
BEGIN
SET #EndIndex = CHARINDEX(#Character, #Input)
INSERT INTO #Output(Item)
SELECT SUBSTRING(#Input, #StartIndex, #EndIndex - 1)
SET #Input = SUBSTRING(#Input, #EndIndex + 1, LEN(#Input))
END
RETURN
END
GO
After Executing this function run this below query
SELECT ID, Department, SaleMngrs,
(SELECT SUM(CONVERT(INT,Item)) FROM dbo.SplitString(SaleMngrs, '$$')) AS Sum
From Temp_Table
solution #2
SELECT ID, Department, SaleMngrs, SUBSTRING_INDEX(SaleMngrs,'$$',1) +
SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(SaleMngrs,'$$0'),'$$',2),'$$',-1) +
SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(SaleMngrs,'$$0'),'$$',3),'$$',-1) +
SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(SaleMngrs,'$$0'),'$$',4),'$$',-1) +
SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(SaleMngrs,'$$0'),'$$',5),'$$',-1) AS SUM
From Temp_Table;
Here is the SQL fiddle URL, you can check here.
http://sqlfiddle.com/#!2/de5066/1
You can convert your data (VARCHAR to INTEGER) and after that get your sum.
By the way could you explain it more? Because Your question is a little puzzling.

After EXEC query I want to proceed further

Empcode Empname COmpany Department Question Scale
-----------------------------------------------------------------------
1001 ABC Comp1 IT Development Opportunities 50
1001 ABC Comp1 IT Goals and Targets Set 30
1001 ABC Comp1 IT Feedback and Coaching 10
1002 XYZ Comp1 IT Goals and Targets Set 60
1002 XYZ Comp1 IT Feedback and Coaching 70
The query I tried:
DECLARE #cols AS NVARCHAR(MAX)
DECLARE #query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT distinct ',' + QUOTENAME(Question)
from TmpTest1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Empcode,Empname,Company,Department,' + #cols + '
from
(
select *
from TmpTest1
) x
pivot
(
max(scale)
for Question in (' + #cols + ')
) p '
execute(#query)
After I execute I want to return the result set and proceed further. How do I do it?
If I understand what you are asking correctly you can create a temporary table and have the result set go into a temporary table where you can do further processing before returning the final results.

Inserting lots of results (more than 1024) of a query into a table dynamically in SQL Server

I have a stored procedure that executes a dynamic query, so I have a string called #template, that along my code is substituted by some instructions so after some handling I have a very big query:
--Init the template and tell it to insert results to TEMPORAL table
SET #template = 'SELECT {LotsOfColumns},{EvenMoreColumns} INTO TEMPORAL FROM '+ #table_name;
--some handling substitute {LotsOfColumns} and {EvenMoreColumns}
--...
--...
-- replace strings
SET #template = REPLACE(#template, '{LotsOfColumns}', #templateLotsOfColumns);
SET #template = REPLACE(#template, '{EvenMoreColumns}', #templateEvenMoreColumns);
--very big query!!
EXEC (#template);
As the TEMPORAL table is a runtime generated, I get a error of 1024 limit column
Msg 4505, Level 16, State 1, Procedure proc, Line 3
exceeds the maximum of 1024 columns.
Is there a way to indicate the table has more than 1024 columns?
Other option I was thinking is:
As I am doing a select statement I am receiving lots of results and insert them into a column, is there a way to change the above query so I am not doing this:
col1 col2 col3 ... col1024 ... col3000
-------------------------------------------
14 34 45 ... 534 ... 657
but this??:
id resultFromquery
--------------
1 1
2 34
3 45
...
1024 534
...
3000 657
I guess this is a better solution... But I do not know how to modify my query:
SET #template = 'SELECT {LotsOfColumns},{EvenMoreColumns} INTO TEMPORAL FROM '+ #table_name;
--some handling sustitute {LotsOfColumns} and {EvenMoreColumns}
EXEC #template;
to do that
You can build dynamically the UNPIVOT syntax as follows in order to get the desidered structure.
set #q='
SELECT CAST(SUBSTRING(col,2,10) AS INT) id, val resultFromquery
FROM '+ #table_name +'
UNPIVOT (val for col in ('+#templateLotsOfColumns+','+#templateEvenMoreColumns+')) unpvt'
exec(#q)
You could try something like this:
create table #temp(id int, [value] int)
truncate table #temp
declare #sql nvarchar(max)
set #sql=''
declare #counter int
set #counter = 1
while(#counter<3001)
begin
set #sql = 'insert into #temp(id, [value])
select #counter, col'+CAST(#counter, varchar(4)) +' from '+#table_name
sp_executesql #sql
set #sql=''
end
But i think your design is seriously flawed if you need to do this kind of thing.
You can use UNPIVOT. I just tested this on a 1025 column result set and that worked OK!
WITH T(col1,col2,col3,col1024,col3000)
AS (
SELECT 14,34,45,534,657
)
SELECT CAST(SUBSTRING(col,4,10) AS INT) id, val AS resultFromquery
FROM T
UNPIVOT (val for col in (col1,col2,col3,col1024,col3000)) unpvt
Returns
id resultFromquery
----------- ---------------
1 14
2 34
3 45
1024 534
3000 657