I have three tables. I need to swith row values into columns.
Table-1: [Approval_Type]
App_ID Type_Ds
2 RMC2
1 RMC1
Table 2: [Project]
Pro_id Summary
1 PROJECT1
2 PROJECT2
Table:3 [Prj_App]
App_Id Pro_Id ExpDt ComDt
1 2 2010-06-05 2010-07-06
1 1 1999-05-05 1999-05-06
2 1 1900-01-01 1900-01-05
I want to display my result as
Pro_Id RMC2 RMC2ExpeDt RMC2ComDt RMC1 RMC1ExpeDt RMC1ComDt
1 RMC2 1900-01-01 1900-01-05 RMC1 1999-05-05 1999-05-06
2 NULL NULL NULL RMC1 2010-06-05 2010-07-06
Below is my query which returns'
DECLARE #SQL1 NVARCHAR(MAX) = ''
DECLARE #SQL NVARCHAR(MAX) = ''
SELECT #SQL1 = STUFF((SELECT ',' + QUOTENAME(Type_Ds) + ',' + QUOTENAME(Type_Ds + ' Expected Date') + ',' + QUOTENAME(Type_Ds + ' Completed Date')
from dbo.AppType
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
print #SQL1
SET #SQL = 'SELECT *
FROM ( SELECT A.Pro_Id,
Type_DS
FROM dbo.Project A left join [dbo].[Prj_App] B on A.Pro_id = B.Pro_Id
right outer join dbo.AppType C on B.App_Id = C.App_ID
) data
PIVOT
( MAX(Type_DS)
FOR Type_DS IN (' + #SQL1 + ')
) pvt1
where Pro_Id is not null'
print #SQL
EXECUTE SP_EXECUTESQL #SQL
Pro_Id RMC2 RMC2ExpeDt RMC2ComDt RMC1 RMC1ExpeDt RMC1ComDt
1 RMC2 NULL NULL RMC1 NULL NULL
2 NULL NULL NULL RMC1 NULL NULL.
can anyone help on it...
My suggestion when you are working with dynamic SQL is to always write the query hard-coded first, so you can get the logic correct, then convert it to dynamic SQL.
Since you are attempting to pivot 3 columns of data I would first unpivot the type_ds, expdt and comdt` columns, then apply the PIVOT function.
The hard-coded version of the query will be:
SELECT *
FROM
(
select pro_id,
type_ds = case
when col ='type_ds'
then type_ds
else type_ds+col end,
value
from
(
SELECT A.Pro_Id,
c.Type_DS,
convert(varchar(10), b.ExpDt, 120) ExpDt,
convert(varchar(10), b.ComDt, 120) ComDt
FROM dbo.Project A
left join [dbo].[Prj_App] B
on A.Pro_id = B.Pro_Id
right outer join dbo.Approval_Type C
on B.App_Id = C.App_ID
) s
cross apply
(
select 'type_ds', type_ds union all
select 'expdt', expdt union all
select 'comdt', comdt
) c (col, value)
) data
PIVOT
(
MAX(value)
FOR Type_DS IN (RMC2, RMC2expdt, RMC2comdt,
RMC1, RMC1expdt, RMC1comdt)
) pvt1
See SQL Fiddle with Demo. Now that you have a working version of the query, you can easily convert it to dynamic SQL:
DECLARE #SQL1 NVARCHAR(MAX) = ''
DECLARE #SQL NVARCHAR(MAX) = ''
SELECT #SQL1 = STUFF((SELECT ',' + QUOTENAME(Type_Ds) + ',' + QUOTENAME(Type_Ds + 'ExpDt') + ',' + QUOTENAME(Type_Ds + 'ComDt')
from dbo.Approval_Type
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #SQL = 'SELECT *
FROM
(
select pro_id,
type_ds = case
when col =''type_ds''
then type_ds
else type_ds+col end,
value
from
(
SELECT A.Pro_Id,
c.Type_DS,
convert(varchar(10), b.ExpDt, 120) ExpDt,
convert(varchar(10), b.ComDt, 120) ComDt
FROM dbo.Project A
left join [dbo].[Prj_App] B
on A.Pro_id = B.Pro_Id
right outer join dbo.Approval_Type C
on B.App_Id = C.App_ID
) s
cross apply
(
select ''type_ds'', type_ds union all
select ''expdt'', expdt union all
select ''comdt'', comdt
) c (col, value)
) data
PIVOT
(
MAX(value)
FOR Type_DS IN (' + #SQL1 + ')
) pvt1 '
--print #SQL
EXECUTE SP_EXECUTESQL #SQL
See SQL Fiddle with Demo
Related
I have a table called tbl_site with 50 columns. I want to write some SQL code that will count the number of distinct values and the number of null values for each column without having to run a statement for each column.
I understand this would possibly include running a nested query to information_schema.columns but I am unsure on how to construct the query further. Also null values would include values that are '' and ' ' if possible.
The desired output would be the following:
Column | Distinct | Null
site_id | 100 | 0
sitearea_id | 12 | 0
site_area | 54 | 5
etc....
Try a mixture of count distinct and sum case:
SELECT Column, count(distinct Column) as 'Distinct'
,sum(case when Column is null then 1 else 0 end) as 'Null'
FROM tbl_site
GROUP BY 1
Yeah, I noticed it's MySQL after i made a script for SQL Server ... but anyway here is the code in case someone needs it ... or if you get idea from it how to do it
declare #position int = 1,
#sql nvarchar(max),
#columnCnt int,
#currentColumn nvarchar(50),
#TableName nvarchar(50) = 'YourTableName',
#DBName nvarchar(50) = 'YourDbName';
if (OBJECT_ID('tempdb..#MyRowCount')) IS NOT NULL DROP TABLE #MyRowCount
CREATE TABLE #MyRowCount (ColumnName nvarchar(50), DistinctCount int, NullCount int)
set #columnCnt = (select MAX(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = #TableName and TABLE_CATALOG = #DBName)
WHILE (#position <= #columnCnt)
BEGIN
set #currentColumn = (select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = #TableName and
TABLE_CATALOG = #DBName and
ORDINAL_POSITION = #position)
set #sql = 'INSERT INTO #MyRowCount (ColumnName, DistinctCount, NullCount)
SELECT ''' + #currentColumn + ''',
(SELECT COUNT(DISTINCT [' + #currentColumn + ']) FROM ' + #TableName + ' where [' + #currentColumn + '] IS NOT NULL),
(SELECT COUNT(*) FROM ' + #TableName + ' where [' + #currentColumn + '] IS NULL)';
-- print #sql;
execute (#sql);
set #position = #position + 1;
END
SELECT * FROM #MyRowCount
In MySQL, you can construct the query using:
set #sql = '
select ''[column]'' as col, count(distinct "[column]"), sum("[column]" is null)
from [table] t
';
select group_concat(replace(replace(#sql, '[table]', table_name), '[column]', column_name) separator ' union all ')
from information_schema.columns
where table_name = ?;
The caveat to this approach is that you need to be sure that your group_concat maximum length value is long enough (the default of 1024 won't get you very far).
Then, you can either copy the query to use prepare/execute to run it.
I want to run a query that shows me all columns from all tables in a database with the datatype varchar and a maximum length of 8000 characters.
This is my code so far.
DECLARE #tabs VARCHAR(MAX);
SET #tabs =
(
SELECT STUFF(( SELECT DISTINCT ',' + [TABLE_NAME]
FROM [DB-Test].INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'VARCHAR' AND
CHARACTER_MAXIMUM_LENGTH = 8000
FOR XML PATH('')), 1, 1, '')
);
DECLARE #cols VARCHAR(MAX)
SET #cols =
(
SELECT STUFF(( SELECT DISTINCT ',' + [TABLE_NAME] + '.' + [COLUMN_NAME]
FROM [DB-Test].INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'VARCHAR' AND
CHARACTER_MAXIMUM_LENGTH = 8000
FOR XML PATH('')), 1, 1, '')
);
DECLARE #query VARCHAR(MAX) = 'SELECT ' + #cols + ' FROM ' + #tabs
EXEC sp_sqlexec #query
When I run the query I get all the column names, but not the values in the columns. It's empty. No 'NULL'-values. As if #cols is interpreted as simple string maybe.
Why?
(When I read out #cols and #tabs they are correct.)
I guess there is one table available in your database which have column with VARCHAR datatype and 8000 length but that table don't have any records. Try by including only those column and table which have at least one record available.
You can try below. Check it and let me know if it works.
DECLARE #tabs VARCHAR(MAX) = ''
; WITH CTE AS
(
SELECT DISTINCT TA.NAME TABLENAME
, SUM(PA.ROWS) OVER (PARTITION BY TA.NAME ) NOOFROW
FROM SYS.TABLES TA
INNER JOIN SYS.PARTITIONS PA ON PA.OBJECT_ID = TA.OBJECT_ID
INNER JOIN SYS.SCHEMAS SC ON TA.SCHEMA_ID = SC.SCHEMA_ID
WHERE TA.IS_MS_SHIPPED = 0 AND PA.INDEX_ID IN (1,0)
), TABLENAME AS
(
SELECT ITBL.[TABLE_NAME]
FROM INFORMATION_SCHEMA.COLUMNS ITBL
WHERE ITBL.DATA_TYPE = 'VARCHAR' AND
ITBL.CHARACTER_MAXIMUM_LENGTH = 8000
AND EXISTS(SELECT 1 FROM CTE WHERE CTE.TABLENAME = ITBL.TABLE_NAME AND CTE.NOOFROW > 0) -- To check no of record available in table
)
SELECT #tabs = #tabs+ISNULL(','+TABLE_NAME, '')
FROM TABLENAME
DECLARE #cols VARCHAR(MAX) = '';
; WITH CTE AS
(
SELECT DISTINCT TA.NAME TABLENAME
, SUM(PA.ROWS) OVER (PARTITION BY TA.NAME ) NOOFROW
FROM SYS.TABLES TA
INNER JOIN SYS.PARTITIONS PA ON PA.OBJECT_ID = TA.OBJECT_ID
INNER JOIN SYS.SCHEMAS SC ON TA.SCHEMA_ID = SC.SCHEMA_ID
WHERE TA.IS_MS_SHIPPED = 0 AND PA.INDEX_ID IN (1,0)
), TABLENAME AS
(
SELECT ITBL.[TABLE_NAME], ITBL.[COLUMN_NAME]
FROM INFORMATION_SCHEMA.COLUMNS ITBL
WHERE ITBL.DATA_TYPE = 'VARCHAR' AND
ITBL.CHARACTER_MAXIMUM_LENGTH = 8000
AND EXISTS(SELECT 1 FROM CTE WHERE CTE.TABLENAME = ITBL.TABLE_NAME AND CTE.NOOFROW > 0) -- To check no of record available in table
)
SELECT #cols = #cols+ISNULL(','+[TABLE_NAME]+'.'+[COLUMN_NAME], '')
FROM TABLENAME
IF LEN(#cols) > 0 AND LEN(#tabs) > 0
BEGIN
DECLARE #query VARCHAR(MAX) = 'SELECT ' + STUFF(#cols,1,1,'') + ' FROM ' + STUFF(#tabs,1,1, '')
EXEC sp_sqlexec #query
END
ELSE
BEGIN
PRINT 'No Column available with data where it''s datatype is VARCHAR and length is 8000'
END
i have a pivot table that display student absence, there is not problem in executing and the result of the pivot but if there is no value it display null, i want to display 0 not a null. i googled and found some ways i try use them but i can't do it. can anyone tell me please?
this my pivot table code:
create proc [dbo].[get_st_abs_by_stage]
#Stage_ID smallint
as
CREATE TABLE #SummaryTable
(
SName nvarchar(50),
CName nvarchar(50),
Stage_ID SmallInt,
Sum_Abs SmallInt
)
delete from #SummaryTable
INSERT INTO #SummaryTable(SName, CName, Stage_ID, Sum_Abs)
SELECT Student_tbl.SName,Courses_tbl.CName,Stages_tbl.Stage_ID,Sum_Abs from Absence_Summary_tbl
inner join Student_tbl on Student_tbl.S_ID = Absence_Summary_tbl.S_ID
inner join Stages_tbl on Stages_tbl.Stage_ID = Student_tbl.Stage_ID
inner join Courses_tbl on Courses_tbl.C_ID = Absence_Summary_tbl.C_ID
where Stages_tbl.Stage_ID = #Stage_ID;
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(CName)
from #SummaryTable
where Stage_ID = #Stage_ID
group by CName
order by CName
FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'')
set #query = 'SELECT SName,' + #cols + ' from
(
select SName, CName, Sum_Abs
from #SummaryTable
) x
pivot
(
sum(Sum_Abs)
for CName in (' + #cols + ')
) p '
execute(#query);
You can generate another variable with isnull for cols. Something like this
select #cols = STUFF((SELECT ',' + QUOTENAME(CName)
from #SummaryTable
where Stage_ID = #Stage_ID
group by CName
order by CName
FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'')
select #isnull_cols = STUFF((SELECT ', isnull(' + QUOTENAME(CName) + ', 0) as ' + QUOTENAME(CName)
from #SummaryTable
where Stage_ID = #Stage_ID
group by CName
order by CName
FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'')
set #query = 'SELECT SName,' + #isnull_cols + ' from
(
select SName, CName, Sum_Abs
from #SummaryTable
) x
pivot
(
sum(Sum_Abs)
for CName in (' + #cols + ')
) p '
execute(#query);
I have OrderInfo table which contains OrderTime(date+time),OrderTrackDate(date),OrderTotal(sales amount) columns as shown in the following image.
1. Table1(Original Table)
Here is the code I have tried so far before pivoting.
SELECT CAST(DATEPART(DAY, OrderTime) as varchar)+'/'+ CAST(DATEPART(MONTH, OrderTime) as varchar)+'/'+CAST(DATEPART(year,OrderTime) as varchar) as daymonthyear,
ROUND(SUM(OrderTotal),2) AS Sales, COUNT(OrderTotal) AS Orders
,datepart(hour,OrderTime) as HH
FROM OrderInfo where OrderTime >= '5/24/2013' AND OrderTrackDate <='5/30/2013'
GROUP BY DATEPART(year, OrderTime),DATEPART(MONTH, OrderTime),DATEPART(day, OrderTime),datepart(hour,OrderTime)
Order By daymonthyear,HH
2. Table 2(Grouped according to Date,Hour from Table1)
How do I pivot dynamically and show sales amount per hour based on Table2?
DESIRED OUTPUT
First of all create a temp table to use it in 3 places - Select columns for pivot, Replace null with zero and inside pivot.
SELECT DISTINCT
SUM(ORDERTOTAL) OVER(PARTITION BY CAST(ORDERTIME AS DATE),DATEPART(HH,ORDERTIME)) [TOTAL],
CONVERT(varchar, CAST(ORDERTIME AS datetime), 103) [DATE],
DATEPART(HH,ORDERTIME) [HOUR],
'HH:'+CAST(DATEPART(HH,ORDERTIME) AS VARCHAR(3)) [HOURCOL]
INTO #NEWTABLE
FROM ORDERTBL
ORDER BY DATEPART(HH,ORDERTIME)
Now declare 2 variables to select columns for pivot and replace null with zero
DECLARE #cols NVARCHAR (MAX)
DECLARE #NullToZeroCols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + [HOURCOL] + ']',
'[' + [HOURCOL] + ']')
FROM (SELECT DISTINCT [HOUR],[HOURCOL] FROM #NEWTABLE) PV
ORDER BY [HOUR]
SET #NullToZeroCols = SUBSTRING((SELECT ',ISNULL(['+[HOURCOL]+'],0) AS ['+[HOURCOL]+']'
FROM(SELECT DISTINCT [HOUR],[HOURCOL] FROM #NEWTABLE GROUP BY [HOUR],[HOURCOL])TAB
ORDER BY [HOUR] FOR XML PATH('')),2,8000)
Now pivot the result
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT [DATE],' + #NullToZeroCols + ' FROM
(
SELECT [HOURCOL],[TOTAL], [DATE] FROM #NEWTABLE
) x
PIVOT
(
SUM([TOTAL])
FOR [HOURCOL] IN (' + #cols + ')
) p
;'
EXEC SP_EXECUTESQL #query
SQL FIDDLE
Hi all I have written the following Procedure to display the results as pivot as per the requirement
DECLARE #values AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #values = STUFF(
(
SELECT DISTINCT ',[' + ColumnName + ']'
FROM xTable
FOR xml path ('')
),1,1,'')
SET #query = 'SELECT viewName1.*, pValues.Code, ' + #values + ' FROM
(
SELECT Column1,Column2, Column3
FROM viewname
) aliasName
PIVOT
(
MAX(value)
FOR ColumnName in (' + #values + ')
) pValues INNER JOIN viewName1 ON pValues.Code = viewname.Code'
EXEC(#query)
But when the value and column names are same in my xTable and viewName1 I am getting that error how can I resolve this. I tried with alas but I am not getting the expected result so can some one help me.
Sample is I am having a ColumnName as TopBrand in my table xTable, this can be a value in my viewName1 like for X Column TopBrand can be a value.
I think you need to have a separate list for FOR and IN clauses and the former should include the alias:
DECLARE #valuesFor AS NVARCHAR(MAX),
#valuesIn AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #valuesFor = STUFF(
(
SELECT DISTINCT N',pValues.[' + ColumnName + ']'
FROM xTable
FOR xml path ('')
),1,1,'')
SELECT #valuesIn = STUFF(
(
SELECT DISTINCT N',[' + ColumnName + ']'
FROM xTable
FOR xml path ('')
),1,1,'')
SET #query = N'SELECT viewName1.*, pValues.Code, ' + #valuesFor + N' FROM
(
SELECT Column1,Column2, Column3
FROM viewname
) aliasName
PIVOT
(
MAX(value)
FOR ColumnName in (' + #valuesIn + N')
) pValues INNER JOIN viewName1 ON pValues.Code = viewname.Code'
EXEC(#query)