SQL Server : creating a view from 2 tables - sql

I have 2 tables, one with hoppers and the ingredients in them (Recorded once a day or when ingredients are changed)
Example:
Hoppers | Ingredients | Timestamp
--------+---------------+----------------------
Hop_1 | Ing_A | 8/22/2016 06:00:00
Hop_2 | Ing_B | 8/22/2016 06:00:00
etc...
And I have a second table that has totals used from each hopper recorded every hour
Example:
Name | Value | Timestamp
-------------------+----------+---------------------
Hop_1 Daily Total | 100 | 8/22/2016 11:00:00
Hop_1 Run Total | 30 | 8/22/2016 11:00:00
etc...
I would like to create a view that shows amount produced from each hopper and says the name.
Example:
Hop_1 Ingredient | Hop_1 Daily | Hop_1 Run | Timestamp
-----------------+-------------+-----------+-------------------
Ing_A | 100 | 30 | 8/22/2016 11:00:00
Sorry if it doesn't look good, I'm new at formatting

For the record I don't really think that structure is the best idea because it requires dynamic sql to pull it off with a couple of loops and lots of LEFT SELF JOINS. But here you go:
IF OBJECT_ID('tempdb..#Ingredients') IS NOT NULL
BEGIN
DROP TABLE #Ingredients
END
IF OBJECT_ID('tempdb..#Totals') IS NOT NULL
BEGIN
DROP TABLE #Totals
END
CREATE TABLE #Ingredients (Hoppers VARCHAR(25), Ingredeients VARCHAR(25), [Timestamp] DATETIME)
CREATE TABLE #Totals (Name VARCHAR(50), Value INT, [Timestamp] DATETIME)
INSERT INTO #Ingredients (Hoppers, Ingredeients, [Timestamp])
VALUES ('Hop_1','Ing_A','8/22/2016 06:00:00'),('Hop_2','Ing_B','8/22/2016 06:00:00'),('Hop_3','Ing_C','8/22/2016 06:00:00')
INSERT INTO #Totals (Name, Value, [Timestamp])
VALUES ('Hop_1 Daily Total',100,'8/22/2016 11:00:00'),('Hop_1 Run Total',30,'8/22/2016 11:00:00'),('Hop_1 Run Total',60,'8/22/2016 09:00:00')
,('Hop_2 Daily Total',500,'8/22/2016 11:00:00'),('Hop_2 Run Total',10,'8/22/2016 11:00:00'),('Hop_2 Run Total',5,'8/22/2016 10:00:00')
,('Hop_3 Daily Total',400,'8/22/2016 11:00:00'),('Hop_3 Run Total',85,'8/22/2016 11:00:00'),('Hop_3 Run Total',65,'8/22/2016 10:00:00')
DECLARE #HopperCount INT
SELECT #HopperCount = COUNT(DISTINCT i.Hoppers)
FROM
#Ingredients i
INNER JOIN #Totals t
ON t.Name LIKE i.Hoppers + '%'
DECLARE #I INT = 1
DECLARE #Sql NVARCHAR(MAX)
SET #Sql = '
;WITH cte AS (
SELECT
i.Hoppers
,i.Ingredeients
,Value
,t.[Timestamp]
,CASE WHEN t.Name LIKE ''%Daily%'' THEN 1 ELSE 0 END as IsDaily
,ROW_NUMBER() OVER (PARTITION BY i.Hoppers, t.name ORDER BY t.[Timestamp] DESC) as RunRowNum
,DENSE_RANK() OVER (PARTITION BY 1 ORDER BY i.Hoppers) as HooperNumber
FROM
#Ingredients i
INNER JOIN #Totals t
ON t.Name LIKE i.Hoppers + ''%''
AND i.[Timestamp] <= t.[Timestamp]
)
SELECT
c.Ingredeients AS [Hop_' + CAST(#I AS VARCHAR(10)) + ' Ingredient]
,SUM(CASE WHEN c.IsDaily = 1 THEN c.Value END) AS [Hop_' + CAST(#I AS VARCHAR(10)) + ' Daily]
,SUM(CASE WHEN c.IsDaily = 0 THEN c.Value END) AS [Hop_' + CAST(#I AS VARCHAR(10)) + ' Run]
,MAX(c.[Timestamp]) AS [Hop_' + CAST(#I AS VARCHAR(10)) + ' Timestamp] '
SET #I = 2
WHILE #I <= ISNULL(#HopperCount,0)
BEGIN
SET #Sql = #Sql + '
,c'+ CAST(#I AS VARCHAR(10)) + '.Ingredeients AS [Hop_' + CAST(#I AS VARCHAR(10)) + ' Ingredient]
,SUM(CASE WHEN c'+ CAST(#I AS VARCHAR(10)) + '.IsDaily = 1 THEN c' + CAST(#I AS VARCHAR(10)) + '.Value END) AS [Hop_' + CAST(#I AS VARCHAR(10)) + ' Daily]
,SUM(CASE WHEN c' + CAST(#I AS VARCHAR(10)) + '.IsDaily = 0 THEN c' + CAST(#I AS VARCHAR(10))+ '.Value END) AS [Hop_' + CAST(#I AS VARCHAR(10)) + ' Run]
,MAX(c' + CAST(#I AS VARCHAR(10)) + '.[Timestamp]) AS [Hop_' + CAST(#I AS VARCHAR(10)) + ' Timestamp] '
SET #I = #I + 1
END
SET #Sql = #Sql + '
FROM
cte c '
SET #I = 2
WHILE #I <= ISNULL(#HopperCount,0)
BEGIN
SET #Sql = #Sql + '
LEFT JOIN cte c' + CAST(#I AS VARCHAR(10)) + '
ON c.HooperNumber + ' + CAST(#I - 1 AS VARCHAR(10)) + ' = c' + CAST(#I AS VARCHAR(10)) + '.HooperNumber
AND c' + CAST(#I AS VARCHAR(10))+ '.RunRowNum = 1
AND c.IsDaily = c' + CAST(#I AS VARCHAR(10)) + '.IsDaily '
SET #I = #I + 1
END
SET #Sql = #Sql + '
WHERE
c.HooperNumber = 1
AND c.RunRowNum = 1
GROUP BY
c.Ingredeients
'
SET #I = 2
WHILE #I <= ISNULL(#HopperCount,0)
BEGIN
SET #Sql = #Sql + ',c' + CAST(#I AS VARCHAR(10)) + '.Ingredeients
'
SET #I = #I + 1
END
EXECUTE (#sql)

You could use a Pivot table for your need.
Here's a link : https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx

Related

Run query for multiple tables and columns

I have the following code, I need to run this code through over 200 tables, can I create a list and a for loop in the variable to go through all the tables and fetch the results for each? Also, how can I include the table name for each row in this query? I also need to go through a list on the column but I can't figure that out from the table list.
DECLARE #table AS VARCHAR(100)
DECLARE #column as varchar(50)
set #table = 'x'
set #column = 'y'
declare #query as varchar(max)
set #query = ' SELECT CAST(MONTH(' + #column + ') AS VARCHAR(2)) + ''-'' + CAST(YEAR(' + #column + ') AS VARCHAR(4)) as date, count(*) as SRC_CNT
FROM ' + #table +
' WHERE ' + #column + ' >= ''2018-01-01'' AND ' + #column + '< ''2021-12-01''
group BY CAST(MONTH(' + #column + ') AS VARCHAR(2)) + ''-'' + CAST(YEAR(' + #column + ') AS VARCHAR(4))
order by date;'
exec(#query)
Rather than loop, I would create a dynamic batch, with all the statements you need, which you can then execute. You can use your best friend to debug the statement(s) if needed:
DECLARE #Column sysname = N'y',
#DateFrom date = '20180101',
#DateTo date = '20211201';
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SELECT #SQL = STRING_AGG(N'SELECT RIGHT(CONVERT(varchar(10),' + QUOTENAME(#Column) + N',105),7) AS [Date],' + #CRLF +
--N' N' + QUOTENAME(t.[name],'''') + N' AS TableName,' + #CRLF + --Uncomment this line if you need it.
N' COUNT(*) AS SRC_CNT' + #CRLF +
N'FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]) + #CRLF +
N'WHERE ' + QUOTENAME(#Column) + N' >= #DateFrom AND ' + QUOTENAME(#Column) + N' < #DateTo' + #CRLF +
N'GROUP BY RIGHT(CONVERT(varchar(10),' + QUOTENAME(#Column) + N',105),7)' + #CRLF +
N'ORDER BY [date];',#CRLF)
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
WHERE EXISTS (SELECT 1
FROM sys.columns c
WHERE c.object_id = t.object_id
AND c.[name] = #Column);
--PRINT #SQL; --Your best friend
EXEC sys.sp_executesql #SQL, N'#DateFrom date, #DateTo date', #DateFrom, #DateTo;
Given tables and sample data:
CREATE TABLE dbo.x(y date, r int);
CREATE TABLE dbo.y(y date, r int);
CREATE TABLE dbo.z(y date, r int);
INSERT dbo.x(y,r) VALUES('20180105',5),
('20180107',6),('20180509',7);
INSERT dbo.y(y,r) VALUES('20180905',5),
('20181007',6),('20181009',7);
INSERT dbo.z(y,r) VALUES('20180605',5),
('20180607',6),('20180609',7);
This dynamic SQL can be generated:
DECLARE #col sysname = N'y',
#StartDate date = '20180101',
#EndDate date = '20211201';
DECLARE #sql nvarchar(max) = N'',
#base nvarchar(max) = N'SELECT [Table Name] = $tblQ$,
[date] = DATEFROMPARTS(YEAR($col$), MONTH($col$), 1),
SRC_CNT = COUNT(*)
FROM dbo.$tbl$ WHERE $col$ >= #s AND y < #e
GROUP BY YEAR($col$), MONTH($col$)';
SELECT #sql = STRING_AGG(REPLACE(REPLACE(REPLACE
(#base, N'$tblQ$', QUOTENAME(t.name, char(39))
),N'$tbl$',QUOTENAME(t.name)), N'$col$', #col), N'
UNION ALL
') + ' ORDER BY [date];'
FROM sys.tables AS t
WHERE EXISTS (SELECT 1 FROM sys.columns
WHERE [object_id] = t.[object_id]
AND name = #col);
PRINT #sql;
EXEC sys.sp_executesql #sql,
N'#s date, #e date',
#StartDate, #EndDate;
Which produces a query like this (only tables that actually have that column name, could be made even safer by making sure they're using a date/time type):
SELECT [Table Name] = 'x',
[date] = DATEFROMPARTS(YEAR(y), MONTH(y), 1),
SRC_CNT = COUNT(*)
FROM dbo.[x] WHERE y >= #s AND y < #e
GROUP BY YEAR(y), MONTH(y)
UNION ALL
SELECT [Table Name] = 'y',
[date] = DATEFROMPARTS(YEAR(y), MONTH(y), 1),
SRC_CNT = COUNT(*)
FROM dbo.[y] WHERE y >= #s AND y < #e
GROUP BY YEAR(y), MONTH(y)
UNION ALL
SELECT [Table Name] = 'z',
[date] = DATEFROMPARTS(YEAR(y), MONTH(y), 1),
SRC_CNT = COUNT(*)
FROM dbo.[z] WHERE y >= #s AND y < #e
GROUP BY YEAR(y), MONTH(y) ORDER BY [date];
That generates output like this:
Table Name
date
SRC_CNT
x
2018-01-01
2
x
2018-05-01
1
z
2018-06-01
3
y
2018-09-01
1
y
2018-10-01
2
Example db<>fiddle
If you really want yyyy-MM instead of yyyy-MM-dd on the output, you can just change this line in the declaration of #base:
[date] = CONVERT(char(7), DATEFROMPARTS(YEAR($col$), MONTH($col$), 1), 120),
And I realized the requirement was MM-yyyy, in which case:
[date] = RIGHT(CONVERT(char(10),
DATEFROMPARTS(YEAR($col$), MONTH($col$), 1), 105), 7),
I usually do the following for tables:
SELECT TABLE_NAME
FROM [<DATABASE_NAME>].INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
You said you could handle columns from there.

Grabbing Null and blank Columns to a table

I'm trying to find a way to grab the count of nulls and blanks of every column in a table and put the results into a table. I found this but don't know how to push it to a table? Would also like to add in a Count(distinct fieldname) as well. Any help would be appreciated!
DECLARE #t nvarchar(max)
SET #t = N'SELECT '
SELECT #t = #t + 'sum(case when ' + c.name + ' is null or ' + c.name + ' = '''' then 1 else 0 end) "' + c.name + '",
sum(case when ' + c.name + ' is null then 0 else 1 end) "Non-Null Values for ' + c.name + '",'
FROM sys.columns c
WHERE c.object_id = object_id('TableName');
SET #t = SUBSTRING(#t, 1, LEN(#t) - 1) + ' FROM TableName;'
EXEC sp_executesql #t
**Edit
This provides the results in one row. Is there a way to do it so each field gets it's own row in a table?
FieldName CountofNullsBlanks
FieldA 0
FieldB 100
Here:
DECLARE #t nvarchar(max)
SET #t = N'SELECT '+convert(nvarchar(max),count(*))+' as [Distinct fieldnames],' -- added the distinct
SELECT #t = #t + 'sum(case when ' + c.name + ' is null or ' + c.name + ' = '''' then 1 else 0 end) "' + c.name + '",
sum(case when ' + c.name + ' is null then 0 else 1 end) "Non-Null Values for ' + c.name + '",'
FROM sys.columns c
WHERE c.object_id = object_id('YOURTABLE');
SET #t = SUBSTRING(#t, 1, LEN(#t) - 1) + 'into ##a FROM YOURTABLE;' --added the into ##a
EXEC sp_executesql #t
Notice the "into ##a" towards the end; This saves the result "table" to a global temp, which will be available until all sessions that accessed it finish. Careful with the name or it might cause conflicts in the database.

Using pivot in SQL Server not returning desired output

I have two tables like this:
**tblTagDescription**
and **tblDataLog**
Now I want to show record of any specific group and in one there might be same group for multiple id in tbltagdescription. And id of tbltagdescription is foreign key for tblDataLog as TagDescID.
Here 'Group1' has 10 ID as from 1 to 10. and there might be multiple record for these ID (from 1 to 10) in tbldatalog. I want these ID from 1 to as columns. For this I used pivot:
DECLARE #COlsID NVARCHAR(MAX)
DECLARE #SQL NVARCHAR(MAX)
DECLARE #Group NVARCHAR(50) = 'Group1'
IF OBJECT_ID('tempdb..##MYTABLE') IS NOT NULL
DROP TABLE ##MYTABLE
SELECT
#COlsID = COALESCE(#ColsID + '],[','') + CONVERT(NVARCHAR(5), z.TagDescID)
FROM
(SELECT DISTINCT TOP 50 tblDataLog.TagDescID
FROM tblDataLog
INNER JOIN tblTagDescription ON tblDataLog.TagDescID = tblTagDescription.ID
ORDER BY tblDataLog.TagDescID) z
SET #COlsID='[' + #COlsID + ']'
SET #SQL='select [DATE],SHIFT, ' + #COlsID + ' into ##MYTABLE from ( select [Date], Value,
(CASE
WHEN ((DATEPART(hour,[DATE]))>6 and (DATEPART(hour,[DATE]))<14) THEN ''A''
WHEN ((DATEPART(hour,[DATE]))>=14 and (DATEPART(hour,[DATE]))<22) THEN ''B''
WHEN ((DATEPART(hour,[DATE]))>=22 or (DATEPART(hour,[DATE]))<6) THEN ''C''
END )AS SHIFT
from tblDataLog )d pivot(max(Value) for TagDescID in (' + #COlsID + ')) piv;'
EXEC (#SQL)
Now when I execute this statement, I get an error:
Invalid column name 'TagDescID'
but there is this column in tbldatalog. How to solve this query?
You need TagDescID column in subquery.
DECLARE #COlsID NVARCHAR(MAX) = ''
DECLARE #COlsAlias NVARCHAR(MAX) = ''
DECLARE #SQL NVARCHAR(MAX)
DECLARE #Group NVARCHAR(50) = 'Group1'
SELECT
#COlsID = #ColsID + ',' + z.TagDescID,
#COlsAlias = #COlsAlias + ',' + z.TagDescID + ' AS ' + z.ReportTag
FROM
(SELECT DISTINCT TOP 50 tblDataLog.TagDescID ID, QUOTENAME(CONVERT(NVARCHAR(5), tblDataLog.TagDescID )) TagDescID, QUOTENAME(tblTagDescription.ReportTag) ReportTag
FROM tblDataLog
INNER JOIN tblTagDescription ON tblDataLog.TagDescID = tblTagDescription.ID
ORDER BY tblDataLog.TagDescID
) z
SET #COlsID= STUFF(#COlsID,1,1,'')
SET #COlsAlias= STUFF(#COlsAlias,1,1,'')
SET #SQL='select [DATE],SHIFT, ' + #COlsAlias + ' into ##MYTABLE from ( select [Date], Value, TagDescID,
(CASE
WHEN ((DATEPART(hour,[DATE]))>6 and (DATEPART(hour,[DATE]))<14) THEN ''A''
WHEN ((DATEPART(hour,[DATE]))>=14 and (DATEPART(hour,[DATE]))<22) THEN ''B''
WHEN ((DATEPART(hour,[DATE]))>=22 or (DATEPART(hour,[DATE]))<6) THEN ''C''
END )AS SHIFT
from tblDataLog )d pivot(max(Value) for TagDescID in (' + #COlsID + ')) piv;'
EXEC (#SQL)

How can I dynamically create columns in SQL select statement

I have 3 tables. Team, Option, OptionTeam.
The Team holds a TeamId and Name
Option holds OptionId, OptionGroup
OptionTeam holds TeamId, OptionId, OptionGroup
select a.TeamId, a.Name
(select count(*) from OptionTeam ot where ot.TeamId=a.TeamId and ot.OptionGroup=4) as Option1,
(select count(*) from OptionTeam ot where ot.TeamId=a.TeamId and ot.OptionGroup=5) as Option2,
(select count(*) from OptionTeam ot where ot.TeamId=a.TeamId and ot.OptionGroup=6) as Option3,
(select count(*) from OptionTeam ot where ot.TeamId=a.TeamId and ot.OptionGroup=11) as Option4
from Team a
I want to get a list of Teams, and extra columns indicating how many options of each group are connected to each Team. This is done by the above query, but I want to replace the 4,5,6,11 with values of OptionGroup from a table Option.
It has to be dynamic, because there might be a new OptionGroup in the future, and I want the stored procedure to be able to handle it.
Sample data:
Team
TeamId
1
2
3
Option
OptionId | OptionGroup
11 | 4
12 | 5
13 | 4
14 | 4
15 | 5
OptionTeam
TeamId | OptionId | OptionGroup
1 | 11 | 4
1 | 13 | 4
2 | 12 | 5
2 | 14 | 4
3 | 15 | 5
And the list I want to get is
TeamId | Group4 (OptionGroup=4) | Group5 (OptionGroup=5)
1 | 2 | 0
2 | 1 | 1
3 | 0 | 1
You'll need a dynamic pivot to do this. Here's the stored procedure:
CREATE PROC [dbo].[pivotsp]
#query AS NVARCHAR(MAX), -- The query, can also be the name of a table/view.
#on_rows AS NVARCHAR(MAX), -- The columns that will be regular rows.
#on_cols AS NVARCHAR(MAX), -- The columns that are to be pivoted.
#agg_func AS NVARCHAR(257) = N'SUM', -- Aggregate function.
#agg_col AS NVARCHAR(MAX), -- Column to aggregate.
#output AS NVARCHAR(257) = N'', -- Table for results
#debug AS bit = 0 -- 1 for debugging
AS
-- Example usage:
-- exec pivotsp
-- 'select * from vsaleshistory',
-- 'market,marketid,family,familyid,Forecaster,Forecasterid,product,productid',
-- 'month',
-- 'sum',
-- 'ku',
-- '##sales'
-- Input validation
IF #query IS NULL OR #on_rows IS NULL OR #on_cols IS NULL
OR #agg_func IS NULL OR #agg_col IS NULL
BEGIN
RAISERROR('Invalid input parameters.', 16, 1);
RETURN;
END
-- Additional input validation goes here (SQL Injection attempts, etc.)
BEGIN TRY
DECLARE
#sql AS NVARCHAR(MAX),
#cols AS NVARCHAR(MAX),
#newline AS NVARCHAR(2);
SET #newline = NCHAR(13) + NCHAR(10);
-- If input is a valid table or view
-- construct a SELECT statement against it
IF COALESCE(OBJECT_ID(#query, N'U'),
OBJECT_ID(#query, N'V')) IS NOT NULL
SET #query = N'SELECT * FROM ' + #query;
-- Make the query a derived table
SET #query = N'(' + #query + N') AS Query';
-- Handle * input in #agg_col
IF #agg_col = N'*'
SET #agg_col = N'1';
-- Construct column list
SET #sql =
N'SET #result = ' + #newline +
N' STUFF(' + #newline +
N' (SELECT N'','' + quotename( '
+ 'CAST(pivot_col AS sysname)' +
+ ') AS [text()]' + #newline +
N' FROM (SELECT DISTINCT('
+ #on_cols + N') AS pivot_col' + #newline +
N' FROM' + #query + N') AS DistinctCols' + #newline +
N' ORDER BY pivot_col' + #newline +
N' FOR XML PATH(''''))' + #newline +
N' ,1, 1, N'''');'
IF #debug = 1
PRINT #sql
EXEC sp_executesql
#stmt = #sql,
#params = N'#result AS NVARCHAR(MAX) OUTPUT',
#result = #cols OUTPUT;
IF #debug = 1
PRINT #cols
-- Create the PIVOT query
IF #output = N''
begin
SET #sql =
N'SELECT *' + #newline +
N'FROM (SELECT '
+ #on_rows
+ N', ' + #on_cols + N' AS pivot_col'
+ N', ' + #agg_col + N' AS agg_col' + #newline +
N' FROM ' + #query + N')' +
+ N' AS PivotInput' + #newline +
N' PIVOT(' + #agg_func + N'(agg_col)' + #newline +
N' FOR pivot_col IN(' + #cols + N')) AS PivotOutput;'
end
ELSE
begin
set #sql = 'IF EXISTS (SELECT * FROM tempdb.sys.objects WHERE ' +
'name = ''' + #output + ''' AND type = N''U'') DROP TABLE tempdb.' + #output
EXEC sp_executesql #sql;
SET #sql =
N'SELECT * INTO ' + #output + #newline +
N'FROM (SELECT '
+ #on_rows
+ N', ' + #on_cols + N' AS pivot_col'
+ N', ' + #agg_col + N' AS agg_col' + #newline +
N' FROM ' + #query + N')' +
+ N' AS PivotInput' + #newline +
N' PIVOT(' + #agg_func + N'(agg_col)' + #newline +
N' FOR pivot_col IN(' + #cols + N')) AS PivotOutput;'
end
IF #debug = 1
PRINT #sql
EXEC sp_executesql #sql;
END TRY
BEGIN CATCH
DECLARE
#error_message AS NVARCHAR(2047),
#error_severity AS INT,
#error_state AS INT;
SET #error_message = ERROR_MESSAGE();
SET #error_severity = ERROR_SEVERITY();
SET #error_state = ERROR_STATE();
RAISERROR(#error_message, #error_severity, #error_state);
RETURN;
END CATCH
With that, it's easy to pivot on a variable number of columns:
EXEC pivotsp
'SELECT TeamID, OptionGroup, OptionID AS Options FROM OptionTeam',
'Teamid', -- Row headers
'optiongroup', -- item to aggregate
'count', -- aggregation function
'optiongroup', -- Column header
'##temp' -- output table name
SELECT * FROM ##temp
Results:
Teamid 4 5
1 2 0
2 1 1
3 0 1
SELECT a.*, o.optionGroup, COUNT(*)
FROM team a
CROSS JOIN
option o
JOIN OptionTeam ot
ON ot.teamId = a.teamId
AND ot.optionGroup = o.optionGroup
WHERE o.OptionId = #id
GROUP BY
a.teamId, o.optionGroup
select teamID,
sum(case when optionGroup = 4 then 1 else 0 end) as optionGroup4,
sum(case when optionGroup = 5 then 1 else 0 end) as optionGroup5,
from optionteam
group by teamID
to add more optiongroups without changing the code, try grouping by that field:
select teamID,optionGroup,count(optionID) as optionCount
from optionteam
group by teamID,optionGroup

SQL Rows to Columns

I have below table structure in MS SQL
AirQuoteID Name SalesValue
7 M 49.50
7 N 23.10
7 +45 233.20
7 +100 233.20
7 +250 2333.10
I want a query which can return
AirQuoteID M N +45 +100 +250
7 49.50 23.10 233.20 233.20 2333.10
What will be the optimum solution. The Values are dynamic
You need to look at the PIVOT operator.
;With T As
(
SELECT 7 AirQuoteID,'M' Name,49.50 SalesValue UNION ALL
SELECT 7 AirQuoteID,'N', 23.10 UNION ALL
SELECT 7 AirQuoteID,'+45',233.20 UNION ALL
SELECT 7 AirQuoteID,'+100',233.20 UNION ALL
SELECT 7 AirQuoteID,'+250',2333.10
)
SELECT AirQuoteID, [M], [N], [+45], [+100], [+250]
FROM T
PIVOT
(
MAX(SalesValue)
FOR Name IN ([M], [N], [+45], [+100], [+250])
) AS pvt;
However if the values for the columns are not fixed you will need to use dynamic SQL.
As the data is dynamic, pivot wont help
http://www.sqlteam.com/article/dynamic-cross-tabs-pivot-tables link posted by #Martin really helped.
first create the below procedure
CREATE PROCEDURE [dbo].[crosstab]
#select varchar(8000),
#sumfunc varchar(100),
#pivot varchar(100),
#table varchar(100)
AS
DECLARE #sql varchar(8000), #delim varchar(1)
SET NOCOUNT ON
SET ANSI_WARNINGS OFF
print ('SELECT ' + #pivot + ' AS [pivot] INTO ##pivot FROM ' + #table + ' WHERE 1=2')
EXEC ('SELECT ' + #pivot + ' AS [pivot] INTO ##pivot FROM ' + #table + ' WHERE 1=2')
EXEC ('INSERT INTO ##pivot SELECT DISTINCT ' + #pivot + ' FROM ' + #table + ' WHERE '
+ #pivot + ' Is Not Null')
SELECT #sql='', #sumfunc=stuff(#sumfunc, len(#sumfunc), 1, ' END)' )
SELECT #delim=CASE Sign( CharIndex('char', data_type)+CharIndex('date', data_type) )
WHEN 0 THEN '' ELSE '''' END
FROM tempdb.information_schema.columns
WHERE table_name='##pivot' AND column_name='pivot'
SELECT #sql=#sql + '''' + convert(varchar(100), [pivot]) + ''' = ' +
stuff(#sumfunc,charindex( '(', #sumfunc )+1, 0, ' CASE ' + #pivot + ' WHEN '
+ #delim + convert(varchar(100), [pivot]) + #delim + ' THEN ' ) + ', ' FROM ##pivot
DROP TABLE ##pivot
SELECT #sql=left(#sql, len(#sql)-1)
SELECT #select=stuff(#select, charindex(' FROM ', #select)+1, 0, ', ' + #sql + ' ')
EXEC (#select)
SET ANSI_WARNINGS ON
GO
The article didnt mention to retrieve data from same table, so below is how you do it
EXECUTE crosstab 'select titles.AirQuoteID from AirSaleQuoteRateSlab titles
inner join
(select distinct AirQuoteID,[Name] from AirSaleQuoteRateSlab) sales
on (sales.AirQuoteID=titles.AirQuoteID)
group by titles.AirQuoteID', 'AVG(titles.SalesValue)','titles.Name','AirSaleQuoteRateSlab titles'
select AirQuoteID,
sum(case Name when 'M' then SalesValue else 0 end) 'M',
sum(case Name when 'N' then SalesValue else 0 end) 'N',
sum(case Name when '+45' then SalesValue else 0 end) '+45',
sum(case Name when '+100' then SalesValue else 0 end) '+100',
sum(case Name when '+250' then SalesValue else 0 end) '+250'
from Table1
group by AirQuoteID