Insert data into different tables in stored procedure - sql-server

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

How to add rows with null data dynamically in result table in SQL Server 2012?

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

SQL Query to find out specific column from all database

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

SQL Server query CTE parent child, works in 2012 local but not in 2012 live, types don't match

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

Showing "Invalid object name " in sqlServer?

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

How To Get All children and itself from Hierarchical data with CTE In SQL Server 2005 using stored procedure

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

Resources