I want to create a dynamic table in SQL Server using dynamic Table name and dynamic Column name. For example:
Table name : 01-02-2015
Column names:
Id 01 02 03.... 28
When I creating a temp table is OK but I want to create a real Table then I use the following script like this, when execute the error occur:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '.01'.
Code:
DECLARE #DynamicSQL as NVARCHAR(max),#TempTableName as nvarchar(max)
DECLARE #TimeSheetDate as DateTime
DECLARE #startDate AS DATETIME --Cursor Local Variables
DECLARE #endDate AS DATETIME
SET #TimeSheetDate = '2015-2-15'
SET #startDate = DATEADD(mm, DATEDIFF(mm, 0, #TimeSheetDate), 0) -- the first day of month
SET #endDate = DATEADD (dd, -1, DATEADD(mm, DATEDIFF(mm, 0, #TimeSheetDate) + 1, 0))-- the last day of month
SET #TempTableName = #startDate -- the first day of month
SET #DynamicSQL='CREATE TABLE dbo.'+ quotename(#TempTableName, '[') + '(Id int identity(1,1) not null primary key);';
WHILE (#startDate <= #endDate)
BEGIN
--DECLARE #DynamicSQL VARCHAR(500)
BEGIN
SET #DynamicSQL = 'ALTER TABLE dbo.' + #TempTableName +
' ADD ['+ CONVERT(VARCHAR(2), #startDate, 105) + '] NVARCHAR(max) NULL'
EXECUTE (#DynamicSQL)
END
SET #startDate = DateADD(dd, 1, #startDate)
IF #startDate - 1 = #endDate
BREAK;
END
exec (#DynamicSQL);
If I use this script to create a temp table is OK:
DECLARE #TempTableName as nvarchar(100)
DECLARE #TimeSheetDate as DateTime
DECLARE #startDate AS DATETIME --Cursor Local Variables
DECLARE #endDate AS DATETIME
SET #TimeSheetDate = '2015-2-15'
SET #startDate = DATEADD(mm, DATEDIFF(mm, 0, #TimeSheetDate), 0)
SET #endDate = DATEADD (dd, -1, DATEADD(mm, DATEDIFF(mm, 0, #TimeSheetDate) + 1, 0))
SET #TempTableName = DATEADD(mm, DATEDIFF(mm, 0, #TimeSheetDate), 0)
if exists (select * from tempdb.dbo.sysobjects o where o.xtype in ('U') and o.id = object_id(N'tempdb..##TempTableName'))
DROP TABLE ##TempTableName
CREATE TABLE ##TempTableName(Id int identity(1,1) not null primary key) -- Creating Temp Table
-- Loop to add columns to temp table
WHILE (#startDate <=#endDate)
BEGIN
DECLARE #DynamicSQL VARCHAR(500)
BEGIN
SET #DynamicSQL = 'ALTER TABLE ##TempTableName ADD ['+ CONVERT(VARCHAR(2),#startDate,105) +'] NVARCHAR(100) NULL'
EXECUTE (#DynamicSQL)
END
SET #startDate = DateADD(dd,1,#startDate)
IF #startDate-1 = #endDate
BREAK;
END
SELECT * FROM ##TempTableName
The problem is in your alter table statement.
Change
SET #DynamicSQL = 'ALTER TABLE dbo.' + #TempTableName +
' ADD ['+ CONVERT(VARCHAR(2), #startDate, 105) + '] NVARCHAR(max) NULL'
To
SET #DynamicSQL = 'ALTER TABLE dbo.' + quotename(#TempTableName, '[') +
' ADD ['+ CONVERT(VARCHAR(2), #startDate, 105) + '] NVARCHAR(max) NULL'
This works for my expectation:
ALTER PROCEDURE [dbo].[proc_InsertTimeSheetInit]
#TimeSheetDate as DateTime
AS
BEGIN
DECLARE #DynamicSQL as NVARCHAR(255)
DECLARE #TableName as nvarchar(255)
DECLARE #startDate AS DATETIME
DECLARE #endDate AS DATETIME
DECLARE #dropSQL as NVARCHAR(255)
SET #startDate = DATEADD(mm, DATEDIFF(mm, 0, #TimeSheetDate), 0) -- the first day of month
SET #endDate = DATEADD (dd, -1, DATEADD(mm, DATEDIFF(mm, 0, #TimeSheetDate) + 1, 0))-- the last day of month
SET #TableName ='TS'+convert(nvarchar(2), datepart(mm, #TimeSheetDate)) + convert(nvarchar(4), datepart(yyyy, #TimeSheetDate))
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].['+ #TableName+ ']') AND type in (N'U'))
SELECT #dropSQL = 'DROP TABLE dbo.' + QUOTENAME(#TableName) + '';
exec (#dropSQL)
SET #DynamicSQL = 'create table [dbo].[' + #TableName + ']([Id] [int] IDENTITY(1,1) NOT NULL,CONSTRAINT PK_'+#TableName+' PRIMARY KEY CLUSTERED (Id))'
exec (#DynamicSQL)
WHILE (#startDate <= #endDate)
BEGIN
BEGIN
SET #DynamicSQL = 'ALTER TABLE [dbo].[' + #TableName + '] ADD ['+ CONVERT(VARCHAR(2), #startDate, 105) + '] NVARCHAR(50) NULL'
EXECUTE (#DynamicSQL)
END
SET #startDate = DateADD(dd, 1, #startDate)
IF #startDate - 1 = #endDate
BREAK;
END
END
I am using dynamic pivot scrip for my report. Below is my script.
DECLARE #Columns VARCHAR(MAX)
set #Columns= ''
SELECT #Columns = #Columns + (QUOTENAME(RTRIM(LTRIM(cast(datename(month, [dates]) as char(15))))+',' + RTRIM(LTRIM(cast(year([dates]) as char(20))))) + ',') FROM efoxsfc.dbo.FTX_FA_Calender
WHERE 1=1
AND CAST(dates AS DATETIME) >= DATEADD(mm, -35 ,DATEADD(m, DATEDIFF(m, 0,GETDATE()), 0))
AND dates <= DATEADD(m, DATEDIFF(m, 0,GETDATE()), 0)
SET #Columns = LEFT(#Columns, LEN(#Columns) - 1)
DECLARE #SQL NVARCHAR(MAX)
set #SQL= ''
SET #SQL =
'WITH BaseData AS
(
select
vendor_code,
RTRIM(LTRIM(cast(datename(month, [CLOSED_DATE]) as char(15))))+'','' + RTRIM(LTRIM(cast(year([CLOSED_DATE]) as char(20)))) as [CLOSED_DATE],
count(vendor_code) as [No. of Case]
from #teamp t WITH (NOLOCK)
where
[CLOSED_DATE] is not null
group by
vendor_code, CLOSED_DATE
)
SELECT *
FROM BaseData
PIVOT
(
sum([No. of Case])
FOR CLOSED_DATE IN (' + #Columns + ')
) AS PivotTable'
EXECUTE sp_executesql #SQL
where will be my isnull function so that will be replace null with zero.
Please advice !!
This is my new Print #SQL
WITH BaseData AS
(
select
vendor_code,
RTRIM(LTRIM(cast(datename(month, [CLOSED_DATE]) as char(15))))+',' + RTRIM(LTRIM(cast(year([CLOSED_DATE]) as char(20)))) as [CLOSED_DATE],
count(vendor_code) as [No. of Case]
from #teamp t WITH (NOLOCK)
where
[CLOSED_DATE] is not null
group by
vendor_code, CLOSED_DATE
)
SELECT ISNULL([November,2012],0)AS[November,2012],ISNULL([December,2012],0)AS[December,2012],ISNULL([January,2013],0)AS[January,2013],ISNULL([February,2013],0)AS[February,2013],ISNULL([March,2013],0)AS[March,2013],ISNULL([April,2013],0)AS[April,2013],ISNULL([May,2013],0)AS[May,2013],ISNULL([June,2013],0)AS[June,2013],ISNULL([July,2013],0)AS[July,2013],ISNULL([August,2013],0)AS[August,2013],ISNULL([September,2013],0)AS[September,2013],ISNULL([October,2013],0)AS[October,2013],ISNULL([November,2013],0)AS[November,2013],ISNULL([December,2013],0)AS[December,2013],ISNULL([January,2014],0)AS[January,2014],ISNULL([February,2014],0)AS[February,2014],ISNULL([March,2014],0)AS[March,2014],ISNULL([April,2014],0)AS[April,2014],ISNULL([May,2014],0)AS[May,2014],ISNULL([June,2014],0)AS[June,2014],ISNULL([July,2014],0)AS[July,2014],ISNULL([August,2014],0)AS[August,2014],ISNULL([September,2014],0)AS[September,2014],ISNULL([October,2014],0)AS[October,2014],ISNULL([November,2014],0)AS[November,2014],ISNULL([December,2014],0)AS[December,2014],ISNULL([January,2015],0)AS[January,2015],ISNULL([February,2015],0)AS[February,2015],ISNULL([March,2015],0)AS[March,2015],ISNULL([April,2015],0)AS[April,2015],ISNULL([May,2015],0)AS[May,2015],ISNULL([June,2015],0)AS[June,2015],ISNULL([July,2015],0)AS[July,2015],ISNULL([August,2015],0)AS[August,2015],ISNULL([September,2015],0)AS[September,2015],ISNULL([October,2015],0)AS[October,2015]FROM BaseData
PIVOT
(
sum([No. of Case])
FOR CLOSED_DATE IN ([November,2012],[December,2012],[January,2013],[February,2013],[March,2013],[April,2013],[May,2013],[June,2013],[July,2013],[August,2013],[September,2013],[October,2013],[November,2013],[December,2013],[January,2014],[February,2014],[March,2014],[April,2014],[May,2014],[June,2014],[July,2014],[August,2014],[September,2014],[October,2014],[November,2014],[December,2014],[January,2015],[February,2015],[March,2015],[April,2015],[May,2015],[June,2015],[July,2015],[August,2015],[September,2015],[October,2015])
) AS PivotTable
This is my new Print #SQL
You need to declare another variable:
DECLARE #Columns2 VARCHAR(MAX) = ''
Then do the main thing:
SELECT #Columns2 = #Columns2 + 'ISNULL(' + (QUOTENAME(RTRIM(LTRIM(cast(datename(month, [dates]) as char(15))))+',' + RTRIM(LTRIM(cast(year([dates]) as char(20))))) + ', 0) AS ' + (QUOTENAME(RTRIM(LTRIM(cast(datename(month, [dates]) as char(15))))+',' + RTRIM(LTRIM(cast(year([dates]) as char(20))))) + ',') FROM efoxsfc.dbo.FTX_FA_Calender
WHERE 1=1
AND CAST(dates AS DATETIME) >= DATEADD(mm, -35 ,DATEADD(m, DATEDIFF(m, 0,GETDATE()), 0))
AND dates <= DATEADD(m, DATEDIFF(m, 0,GETDATE()), 0)
SET #Columns2 = LEFT(#Columns2, LEN(#Columns2) - 1)
Then use it like:
...
SELECT ' + #Columns2 + '
FROM BaseData
PIVOT
...
I have store procedure like this:
ALTER procedure [dbo].[ParkingSummary1] #startdate varchar(100), #enddate varchar(100) as begin
declare #date1 datetime = CONVERT(datetime, #startdate + ' 00:01:00.000', 120);
declare #date2 datetime = CONVERT(datetime, #enddate + ' 23:23:59.000', 120);
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(Vtype)
from VType_tbl
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT LocName, ' + #cols + '
from
( select l.LocName,Vtype from Transaction_tbl t join VType_tbl v on t.vtid = v.vtid
join dbo.Location_tbl l on t.locid=l.Locid where dtime between '''+ #date1+''' and '''+#date2+''' and Status = 5 ) d
pivot
(
count(Vtype)
for Vtype in (' + #cols + ')
) p ' exec sys.sp_executesql #query
end
.while am passing startand enddate like this:
#startdate = '2013-08-05',#enddate = '2013-08-08'
am getting error like this:Conversion failed when converting date and/or time from character string.
what is wrong with my stored procedure ? instead of Date1 and date2 if i pass startdate and enddate then it will work.but that time if i given same date then not coming any result
I would use SET DATEFORMAT YMD as the first line of your stored procedure.
ALTER procedure [dbo].[ParkingSummary1] #startdate varchar(100), #enddate varchar(100)
AS
BEGIN
SET DATEFORMAT DMY
declare #date1 datetime = CONVERT(datetime, #startdate + ' 00:01:00.000', 120);
declare #date2 datetime = CONVERT(datetime, #enddate + ' 23:23:59.000', 120);
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(Vtype)
from VType_tbl
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT LocName, ' + #cols + '
from
( select l.LocName,Vtype from Transaction_tbl t join VType_tbl v on t.vtid = v.vtid
join dbo.Location_tbl l on t.locid=l.Locid where dtime between '''+ #date1+''' and '''+#date2+''' and Status = 5 ) d
pivot
(
count(Vtype)
for Vtype in (' + #cols + ')
) p ' exec sys.sp_executesql #query
END
I had to replace
declare #date1 datetime = CONVERT(datetime, #startdate + ' 00:01:00.000', 120);
declare #date2 datetime = CONVERT(datetime, #enddate + ' 23:23:59.000', 120);
by
declare #date1 nvarchar(100) = convert(varchar, #startdate+' 00:00:00.000', 120)
declare #date2 nvarchar(100) = convert(varchar, #enddate+' 23:59:59.000', 120)
I have stored procedure like this on my DB:
ALTER procedure [dbo].[performance]
(#startdate nvarchar(100), #enddate nvarchar(100)
as begin
declare #date1 nvarchar(100) = convert(varchar, #startdate+' 00:00:00.000', 120)
declare #date2 nvarchar(100) = convert(varchar, #enddate+' 23:59:59.000', 120)
set NOCOUNT on;
select l.LocName,v.Vtype, SUM(DATEDIFF(MI,t.Paydate,t.DelDate)) as TotalDiff,
[dbo].[testfunction](
CONVERT(decimal(10,1), AVG( CONVERT(NUMERIC(18,2), DATEDIFF(SS,t.Paydate,t.DelDate) ) ))) as Average
from Transaction_tbl t
left join VType_tbl v
on t.vtid=v.vtid
left join Location_tbl l
on t.Locid=l.Locid
where t.Locid in
(select t1.Locid from Transaction_tbl t1)
and dtime between '' + #date1 +'' and ''+ #date2 +''
and Status =5
group by v.Vtype,l.LocName,l.Locid order by l.Locid
end
my testfunction ike this:
ALTER FUNCTION [dbo].[testfunction] (#dec NUMERIC(18, 2)) RETURNS Varchar(50)
AS
BEGIN
DECLARE
#hour integer,
#Mns integer,
#second decimal(18,3)
DECLARE #Average Varchar(50)
select #hour=CONVERT(int,#dec/60/60)
SELECT #Mns = convert(int, (#dec / 60) - (#hour * 60 ));
select #second=#dec % 60;
SELECT #Average =
convert(varchar(9), convert(int, #hour)) + ':' +
right('00' + convert(varchar(2), convert(int, #Mns)), 2) + ':' +
right('00' + CONVERT(decimal(10,0), convert(varchar(6), #second)), 6)
RETURN #Average
END
if i pass start date:2013-06-01 and end date:2013-08-01 then getting proper out put
if i pass start date:2010-06-01 and end date:2013-08-01 (bigger date difference) then getting error:
Arithmetic overflow error converting numeric to data type varchar.
i know having some problem with my function.but i am not able find out what is the issue with my function.if any one please help me to find out
try this .. i think your #Mns should be the problem
ALTER FUNCTION [dbo].[testfunction] (#dec NUMERIC(18, 2)) RETURNS Varchar(50)
AS
BEGIN
DECLARE
#hour decimal(18,2),
#Mns decimal(18,2),
#second decimal(18,3)
DECLARE #Average Varchar(50)
select #hour=CONVERT(int,#dec/60/60)
SELECT #Mns = convert(int, (#dec / 60) - (#hour * 60 ));
select #second=#dec % 60;
SELECT #Average =
convert(varchar(9), convert(int, #hour)) + ':' +
right('00' + convert(varchar(8), convert(decimal(18,2), #Mns)), 2) + ':' +
right('00' + CONVERT(decimal(10,0), convert(varchar(10), #second)), 6)
RETURN #Average
END
ALTER procedure [dbo].[performance]
#startdate nvarchar(100),
#enddate nvarchar(100)
as begin
set NOCOUNT on;
select l.LocName,
v.Vtype,
SUM(DATEDIFF(MI,t.Paydate,t.DelDate)) as TotalDiff,
[dbo].[testfunction](CONVERT(decimal(10,1), AVG(
CONVERT(NUMERIC(18,2), DATEDIFF(SS,t.Paydate,t.DelDate) ) ))) as Average
from
Transaction_tbl t
left join
VType_tbl v
on t.vtid=v.vtid
left join
Location_tbl l
on t.Locid=l.Locid
where
t.Locid in(select t1.Locid from Transaction_tbl t1) and
dtime between '' + #startdate +'' and ''+#enddate+'' and
Status =5
group by v.Vtype,l.LocName,l.Locid order by l.Locid
end
also i have one function like this:
ALTER FUNCTION [dbo].[testfunction] (#dec NUMERIC(18, 2)) RETURNS Varchar(50)
AS
BEGIN
DECLARE
#hour integer,
#Mns integer,
#second decimal(18,3)
DECLARE #Average Varchar(50)
select #hour=CONVERT(int,#dec/60/60)
SELECT #Mns = convert(int, (#dec / 60) - (#hour * 60 ));
select #second=#dec % 60;
SELECT #Average =
convert(varchar(9), convert(int, #hour)) + ':' +
right('00' + convert(varchar(2), convert(int, #Mns)), 2) + ':' +
right('00' + CONVERT(decimal(10,0), convert(varchar(6), #second)), 6)
RETURN #Average
END
am passing date like this:2013-01-01 and 2013-05-01
while executing this am getting error:Arithmetic overflow error converting numeric to data type varchar.
Try this one -
ALTER PROCEDURE [dbo].[performance]
#startdate NVARCHAR(100), --<-- try to use date datatype - DATE, DATETIME, ...
#enddate NVARCHAR(100)
AS
BEGIN
SET NOCOUNT ON;
SELECT
l.LocName
, v.Vtype
, SUM(DATEDIFF(MI, t.Paydate, t.DelDate)) AS TotalDiff
, [dbo].[testfunction](
CONVERT(DECIMAL(10, 1), AVG(CONVERT(NUMERIC(18, 2), DATEDIFF(SS, t.Paydate, t.DelDate))))
) AS Average
FROM dbo.Transaction_tbl t
LEFT JOIN dbo.VType_tbl v ON t.vtid = v.vtid
LEFT JOIN dbo.Location_tbl l ON t.Locid = l.Locid
WHERE dtime BETWEEN
CAST(#startdate AS DATETIME)
AND
CAST(#enddate AS DATETIME) --<-- possible problem
AND [status] = 5
--AND t.Locid IN (SELECT t1.Locid FROM Transaction_tbl t1) --<-- unnessesary
GROUP BY
v.Vtype
, l.LocName
, l.Locid
ORDER BY l.Locid
END
Update:
ALTER FUNCTION [dbo].[testfunction]
(
#dec NUMERIC(18, 2)
)
RETURNS Varchar(50)
AS BEGIN
DECLARE
#hour BIGINT
, #Mns BIGINT
, #second DECIMAL(18,3)
SELECT
#hour = CONVERT(BIGINT, #dec / 60 / 60)
, #Mns = CONVERT(BIGINT, (#dec / 60) - (#hour * 60))
, #second = #dec % 60
RETURN
CONVERT(VARCHAR(50), CONVERT(BIGINT, #hour)) + ':' + --<-- VARCHAR(9) => VARCHAR(50)
RIGHT('00' + CONVERT(VARCHAR(2), CONVERT(BIGINT, #Mns)), 2) + ':' +
RIGHT('00' + CONVERT(DECIMAL(2, 0), CONVERT(VARCHAR(6), #second)), 6)
END