Following is the original SP which always inserts into table1 (INSERT INTO table1). Now I need to insert either into table1 or table2 which both have the same structure.
I tried to pass the tableName as parameter into SP.
ALTER PROCEDURE [dbo].[sp_importStats] (
#accountID BIGINT,
#csvFileName VARCHAR (1024),
#csvFormatFileName VARCHAR (1024)
#tableName VARCHAR(256))
Then I tried to INSERT using EXECUTE as following:
--Incorrect syntax near EXECUTE.
EXECUTE(
'INSERT INTO '+ #tableName + '(accountId, date, cost)
(SELECT cte.id, ms.date, ms.cost
FROM #stats ms
INNER JOIN CTE cte ON ms.accountNumber = cte.key4)');
Then I tried this:
--Must declare the table variable #tableName.
INSERT INTO #tableName (accountId, date, cost)
(SELECT cte.id, ms.date, ms.cost
FROM #stats ms
INNER JOIN CTE cte ON ms.accountNumber = cte.key4);
Then I tried not to pass the tableName and instead pass a boolean into SP and based on that decide which table I need to insert to:
ALTER PROCEDURE [dbo].[sp_importStats] (
#accountID BIGINT,
#csvFileName VARCHAR (1024),
#csvFormatFileName VARCHAR (1024),
#condition BIT = 0)
IF (#condition= 0)
SET #table = 'table1'
ELSE
SET #table = 'table2'
--Must declare the table variable "#table".
INSERT INTO #table (accountId, date, cost)
(SELECT cte.id, ms.date, ms.cost
FROM #sats ms
INNER JOIN CTE cte ON ms.accountNumber = cte.key4);
I got error either way. Would you please let me know what's the best way to handle this? Why am I receiving these errors? Any help is greatly appreciated.
Original SP:
ALTER PROCEDURE [dbo].[sp_importStats] (
#accountID BIGINT,
#csvFileName VARCHAR (1024),
#csvFormatFileName VARCHAR (1024))
AS
BEGIN
CREATE TABLE #stats(
[accountID] [bigint] NOT NULL,
[accountNumber] [varchar](30) NULL,
[date] [datetime] NOT NULL,
[cost] [money] NULL,
);
EXECUTE('INSERT INTO #stats SELECT * FROM '+
'OPENROWSET (BULK N''' + #csvFileName + '''' +
',FORMATFILE='''+#csvFormatFileName+''''+
',FIRSTROW=2'+
',MAXERRORS=0'+
') AS t;');
WITH CTE(id, key4) AS (
SELECT A.id, A.[key4]
FROM VA A (NOLOCK)
WHERE A.id = #accountID
UNION ALL
SELECT A.id, A.[key4]
FROM VA A (NOLOCK)
INNER JOIN CTE ON (CTE.id = A.MAID)
WHERE A.key4 IS NOT NULL
)
INSERT INTO table1 (accountId, date, cost)
(SELECT cte.id, ms.date, ms.cost
FROM #stats ms
INNER JOIN CTE cte ON ms.accountNumber = cte.key4);
DROP TABLE #stats;
END
This is what I have now:
ALTER PROCEDURE [dbo].[sp_importStats] (
#accountID BIGINT,
#csvFileName VARCHAR (1024),
#csvFormatFileName VARCHAR (1024)
#tableName VARCHAR(256))
AS
BEGIN
DECLARE #sql NVARCHAR(MAX);
CREATE TABLE #stats(
[accountID] [bigint] NOT NULL,
[accountNumber] [varchar](30) NULL,
[date] [datetime] NOT NULL,
[cost] [money] NULL,
);
EXECUTE('INSERT INTO #stats SELECT * FROM '+
'OPENROWSET (BULK N''' + #csvFileName + '''' +
',FORMATFILE='''+#csvFormatFileName+''''+
',FIRSTROW=2'+
',MAXERRORS=0'+
') AS t;');
WITH CTE(id, key4) AS (
SELECT A.id, A.[key4]
FROM VA A (NOLOCK)
WHERE A.id = #accountID
UNION ALL
SELECT A.id, A.[key4]
FROM VA A (NOLOCK)
INNER JOIN CTE ON (CTE.id = A.MAID)
WHERE A.key4 IS NOT NULL
)
--Incorect synstax near SET.
SET #sql = 'INSERT INTO '+ QUOTENAME(#tableName) + '(accountId, date, cost)
(SELECT cte.id, ms.date, ms.cost
FROM #stats ms
INNER JOIN CTE cte ON ms.accountNumber = cte.key4)';
EXECUTE sp_executesql #sql;
DROP TABLE #stats;
END
Passing Table Name as Parameter
Use QUOTENAME() Function to put square brackets around your table names to tell sql server explicitly that it is a Sql Server Object name something like this ..
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N';WITH CTE(id, key4) AS (
SELECT A.id, A.[key4]
FROM VA A (NOLOCK)
WHERE A.id = #accountID
UNION ALL
SELECT A.id, A.[key4]
FROM VA A (NOLOCK)
INNER JOIN CTE ON (CTE.id = A.MAID)
WHERE A.key4 IS NOT NULL
)
INSERT INTO ' + QUOTENAME(#tableName) +' (accountId, date, cost)
SELECT cte.id, ms.date, ms.cost
FROM #stats ms
INNER JOIN CTE cte ON ms.accountNumber = cte.key4;'
EXECUTE sp_executesql #Sql
Using QUOTENAME() Function can protect you against a possible sql injection attack. Also you do not need parenthesis around your select statement.
Also you should avoid using sp_ prefix for you stored Procedure names. Read Here why.
Using IF..ELSE Blocks
IF (Some_Condition IS TRUE)
BEGIN
/* Insert Statement For Table One*/ --<-- No need to use table Names as variable
END -- just hardcode the table names in your
ELSE -- Insert Statements
BEGIN
/* Insert Statement For Table Two*/
END
Did you notice that you missed a comma in declaration.
ALTER PROCEDURE [dbo].[sp_importStats] (
#accountID BIGINT,
#csvFileName VARCHAR (1024),
#csvFormatFileName VARCHAR (1024),---comma missing here
#tableName VARCHAR(256))
Related
I have this table with 22 rows as above
I am getting a converted table as above
I created following procedure in order to get result table
ALTER PROCEDURE [dbo].[proc_YS_BAB_IR_Item]
#UserId int
AS
BEGIN TRAN
DECLARE #SqlQry NVARCHAR(MAX);
SET #SqlQry = N''
DECLARE #Cnt INT = 1, #EndCnt INT = 25,
#v_UserId INT = CAST(#UserId AS VARCHAR(MAX));
CREATE TABLE #TempColumns
(
Calculate_ItemIdentifier VARCHAR(MAX),
SeqOrder INT
)
WHILE #cnt <= #EndCnt
BEGIN
INSERT INTO #TempColumns
SELECT
'IR'+ CAST(#Cnt AS VARCHAR(MAX)),
#Cnt
SET #Cnt = #Cnt + 1;
END
DECLARE #DATA VARCHAR(10), #DATA1 VARCHAR(10) = '000000'
DECLARE #zero_str VARCHAR(6) = '000000'
-- Generate table alike to yours
DECLARE #yourTable TABLE ([value] varchar(max))
-- convert array to xml
;WITH cte AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS rn,
[response],
CAST('<a>'+REPLACE(SUBSTRING([response],2,LEN([response]) - 2),',','</a><a>')+'</a>' as xml) AS x,
#v_UserId AS UserId,
[item_identifier]
FROM
#TempColumns
LEFT JOIN
YS_BAB_response_dump ON YS_BAB_response_dump.Item_Identifier = #TempColumns.Calculate_ItemIdentifier
AND UserId = CAST(#UserId AS VARCHAR(MAX))
AND TestModel = 'IR'
)
-- do the stuff
SELECT
c.rn,
c.[response],
c.[item_identifier],
RIGHT(#zero_str +
CAST(SUM(CAST(STUFF(#zero_str,t.c.value('.','tinyint')+1,1,'1') AS INT)) AS VARCHAR(6)), 6) AS ans,
c.UserId
FROM
cte c
CROSS APPLY
x.nodes('/a') AS t(c)
GROUP BY
c.rn, c.[response], c.UserId, c.[Item_Identifier]
ORDER BY
c.rn
COMMIT TRAN
What changes I need to do in above procedure to get 25 records as a result instead of 22, For IR21,IR22 and IR25 I want null data in response and ans columns for that respective userId? May i need to use some other function instead of CROSS APPLY? How it will be?
You were almost there. Use OUTER APPLY instead of CROSS APPLY
I wanted to find out the columns which contains the word "VAP" or cancellation. but the problem is we have several number of databases in our server. I wanted to know in which database/table contains the columns name which consist these words. Can anyone let us know if there is any query which can be used to search column name from all databases? I have tried below query but it will only help to find from a single database.
select distinct
t.name as TableName,
SCHEMA_NAME(t.schema_id) as TableSchema,
c.name as ColumnName,
ct.name as ColumnDataType,
c.is_nullable as IsNullable
from
sys.tables t with(nolock)
inner join
sys.columns c with(nolock) on t.object_id = c.object_id
inner join
sys.types ct with(nolock) on ct.system_type_id = c.system_type_id
where
c.name like '%VAP%'
order by
t.name
If you need to find database objects (e.g. tables, columns, triggers) by name - have a look at the FREE Red-Gate tool called SQL Search which does this - it searches your entire database for any kind of string(s).
It's a great must-have tool for any DBA or database developer - did I already mention it's absolutely FREE to use for any kind of use??
I know this is little lengthy, But You can use this query if you do not wish to use any third party applications
USE [master]
GO
DECLARE #Search VARCHAR(50)='A',#SQL VARCHAR(MAX)
DECLARE #Min INT,#Max INT
DECLARE #Table TABLE
(
SeqNo INT IDENTITY(1,1),
DatabaseNm VARCHAR(255),
TableName VARCHAR(255),
ColumnName VARCHAR(255)
)
DECLARE #TEMP TABLE
(
SeqNo INT IDENTITY(1,1),
Qry VARCHAR(MAX)
)
INSERT INTO #TEMP
(
Qry
)
SELECT
Qry = 'SELECT
DbNm = '''+name+''',
TblNm = [TABLE_SCHEMA]+''.''+[TABLE_NAME],
COlNm = COLUMN_NAME
FROM ['+name+'].INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE ''%'+ISNULL(#Search,'')+'%'''
FROM sys.databases
SELECT
#Min = MIN(SeqNo),
#Max = MAX(SeqNo)
FROM #TEMP
WHILE ISNULL(#Min,0)<=ISNULL(#Max,0)
BEGIN
SELECT
#SQL = Qry
FROM #TEMP
WHERE SeqNo = #Min
INSERT INTO #Table
(
DatabaseNm,
TableName,
ColumnName
)
EXEC(#SQL)
SELECT
#Min = ISNULL(#Min,0)+1
END
SELECT
*
FROM #Table
Use sp_MSForeachdb for getting details. Try below query.
-------------------------
create table #temp
(dbname varchar(100),
tablename varchar(100)
)
EXECUTE master..sp_MSForeachdb '
USE [?]
IF ''?'' <> ''master'' AND ''?'' <> ''model'' AND ''?'' <> ''msdb'' AND ''?'' <> ''tempdb''
BEGIN
IF (EXISTS (SELECT *
FROM INFORMATION_SCHEMA.columns where COLUMN_NAME = ''VAP''))
BEGIN
insert into #temp
select ''?'',table_name FROM INFORMATION_SCHEMA.columns where COLUMN_NAME = ''VAP''
end
END
'
select * from #temp
This query works in one server version but not in another.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[EventDetails]
#EventID AS VARCHAR(20)
AS
BEGIN
WITH CTE(CategoryID, FullCategName, OrderString) AS
(
SELECT
CategoryID,
CAST(CategoryName AS VARCHAR(MAX)),
CAST(CAST(CategoryID AS CHAR(5)) AS VARCHAR(MAX)) OrderString
FROM
CategoryTbl
WHERE
ParentCategoryIDf is NULL
UNION ALL
SELECT
p.CategoryID,
CAST(c.FullCategName + ' >> ' + p.CategoryName AS VARCHAR(MAX)),
CAST(c.OrderString + CAST(p.CategoryID AS CHAR(5)) AS VARCHAR(MAX)) OrderString
FROM
CategoryTbl p
JOIN
CTE c ON c.CategoryID = p.ParentCategoryIDf
)
SELECT
(SELECT TOP 1 i.ImageUrl
FROM ImageTbl i
WHERE i.ProductIDf = p.EventID) AS ImageURL, *
FROM
EventTbl p
LEFT JOIN
CTE c on c.CategoryID = p.CategoryIDf
WHERE
p.EventID = #EventID
END
This is probably a collation issue, try this:
WITH CTE(CategoryID, FullCategName, OrderString) AS (
SELECT
CategoryID
, cast(CategoryName as varchar(max)) Collate SQL_Latin1_General_CP1_CI_AS as FullCategName
, cast(cast(CategoryID as char(5)) as varchar(max)) Collate SQL_Latin1_General_CP1_CI_AS as OrderString
FROM CategoryTbl
WHERE ParentCategoryIDf is NULL
UNION ALL
SELECT
p.CategoryID
, cast(c.FullCategName + ' >> ' + p.CategoryName as varchar(max)) Collate SQL_Latin1_General_CP1_CI_AS
, cast(c.OrderString + cast(p.CategoryID as char(5)) as varchar(max)) Collate SQL_Latin1_General_CP1_CI_AS --OrderString
FROM CategoryTbl p
JOIN CTE c
ON c.CategoryID = p.ParentCategoryIDf
)
select
(select top 1 i.ImageUrl
from ImageTbl i
where i.ProductIDf=p.EventID) as ImageURL
, *
from EventTbl p
left join CTE c on c.CategoryID=p.CategoryIDf
where p.EventID=#EventID
end
Reference:
T-SQL CTE Error: Types don't match between the anchor and the recursive part
While Executing the Following query it showing the Invalid object name '#temp1'. can any body knows the error occurred due to which reason this is my orginal code i used to fetch code , her differnt tables are formed i need to get the sum of the each row of each table
DECLARE #t TABLE (
id int IDENTITY(1,1),
BranchName nvarchar(max)
)
DECLARE #n int = 0,
#i int = 1,
#BranchName nvarchar(max),
#sql nvarchar(max),
#columns nvarchar(max)
INSERT INTO #t
SELECT DISTINCT BranchName
FROM ALX_Branches
SELECT #n = ##ROWCOUNT
WHILE #n >= #i
BEGIN
SELECT #BranchName = BranchName
FROM #t
WHERE id = #i
SELECT #columns = (
SELECT DISTINCT ','+QUOTENAME([SubInventory])
FROM #MyTempTable
WHERE [BranchName] = #BranchName
FOR XML PATH('')
)
SELECT #sql = N'--
SELECT * into #temp1
FROM (
SELECT [BranchID],
[SubInventory],
[Product],
[Stock]
FROM #MyTempTable
WHERE [BranchName] = ''' +#BranchName +'''
) as t
PIVOT (
MAX([Stock]) FOR [SubInventory] IN ('+STUFF(#columns,1,1,'')+')
) as pvt'
EXEC sp_executesql #sql
select * from #temp1
Firstly, there is no need for creating #temp1 table before.
because you are using "Select * into" that already create table within it.
Suppose type this note as a comment, but I don't have enough reputation score.
The reason of
Invalid object name '#temp1'
is: the variable #sql is NULL because #temp1 is not created yet via "Select * into" clause.
so append selecting from #temp1 within dynamic sql as the following:
SELECT #sql = N'--
SELECT * into #temp1
FROM (
SELECT [BranchID],
[SubInventory],
[Product],
[Stock]
FROM #MyTempTable
WHERE [BranchName] = ''' +#BranchName +'''
) as t
PIVOT (
MAX([Stock]) FOR [SubInventory] IN ('+STUFF(#columns,1,1,'')+')
) as pvt
select * from #temp1 '
EXEC sp_executesql #sql
I have many similar structure tables like this:
CREATE TABLE [dbo].[tbl_Hierarchy](
[ID] [int] NOT NULL,
[ParentID] [int] NOT NULL,
[Text] [nvarchar](100) NOT NULL,
--other field irrelevant to my question
)
INSERT INTO dbo.tbl_Hierarchy VALUES(1,0,'parent1')
INSERT INTO dbo.tbl_Hierarchy VALUES(2,0,'parent2')
INSERT INTO tbl_Hierarchy VALUES(3,1,'child1')
INSERT INTO tbl_Hierarchy VALUES(4,3,'grandchild1')
INSERT INTO tbl_Hierarchy VALUES(5,2,'child2')
Can you help me writing such as a stored procedure including two parameters with table name and ID ?
For example, when executing
EXEC usp_getChildbyID tbl_Hierarchy, 1
the result set should be:
ID Text Level
1 parent1 1
3 child1 2
4 grandchild1 3
Thanks a lot in advance.
This recursive CTE should do the trick.
WITH RecursiveCte AS
(
SELECT 1 as Level, H1.Id, H1.ParentId, H1.Text FROM tbl_Hierarchy H1
WHERE id = #Id
UNION ALL
SELECT RCTE.level + 1 as Level, H2.Id, H2.ParentId, H2.text FROM tbl_Hierarchy H2
INNER JOIN RecursiveCte RCTE ON H2.ParentId = RCTE.Id
)
SELECT Id, Text, Level FROM RecursiveCte
If you really want it with a dynamic table in a procedure this could be a solution
CREATE PROCEDURE usp_getChildbyID
#TableName nvarchar(max),
#Id int
AS
BEGIN
DECLARE #SQL AS nvarchar(max)
SET #SQL =
'WITH RecursiveCte AS
(
SELECT 1 as Level, H1.Id, H1.ParentId, H1.Text FROM ' + #TableName + ' H1
WHERE id = ' + CAST(#Id as Nvarchar(max)) + '
UNION ALL
SELECT RCTE.level + 1 as Level, H2.Id, H2.ParentId, H2.text FROM ' + #TableName + ' H2
INNER JOIN RecursiveCte RCTE ON H2.ParentId = RCTE.Id
)
select Id, Text, Level from RecursiveCte'
EXEC sp_executesql #SQL;
END
Edit:
Sql fiddle example: http://sqlfiddle.com/#!3/d498b/22