Select only few columns from procedure and insert into table - sql

I have a stored procedure that returns 6 columns. But I want to take only 2 columns and insert them into my table variable.
DECLARE #CategoryTable TABLE(
CategoryId Int NOT NULL,
Name nvarchar(255) NOT NULL
)
INSERT INTO #CategoryTable EXEC [GetAllTenantCategories] #TenantId
When I run this
Column name or number of supplied values does not match table
definition
How to insert only specified columns from a stored procedure?
I do not want to use SELECT INTO as it is not supported by SQL Azure
Tried below and got Invalid object name '#Temp'
DECLARE #CategoryTable TABLE(
CategoryId Int NOT NULL,
Name nvarchar(255) NOT NULL
)
INSERT INTO #Temp EXEC [GetAllTenantCategories] 1
INSERT INTO #CategoryTable (CategoryId, Name)
SELECT CategoryId, Name from #Temp
DROP TABLE #Temp

You can create a temp table first and the INSERT the required columns in your table variable.
CREATE TABLE #temp
(
your columns and datatype
)
INSERT INTO #temp
EXEC [GetAllTenantCategories] #TenantId
Then you can,
DECLARE #CategoryTable TABLE(
CategoryId Int NOT NULL,
Name nvarchar(255) NOT NULL
)
INSERT INTO #CategoryTable (CategoryId, Name)
select CategoryId, Name from #temp
Also drop the #temp table,
DROP TABLE #temp

Refer the points taken from https://www.simple-talk.com/sql/performance/execution-plan-basics/
When the Estimated Plan is Invalid
In some instances, the estimated plan won't work at all. For example, try generating an estimated plan for this simple bit of code:
CREATE TABLE TempTable
(
Id INT IDENTITY (1 , 1 )
,Dsc NVARCHAR (50 )
);
INSERT INTO TempTable ( Dsc )
SELECT [Name]
FROM [Sales] .[Store] ;
SELECT *
FROM TempTable ;
DROP TABLE TempTable ;
You will get this error:
Invalid object name 'TempTable'.
The optimizer, which is what is used to generate Estimated Execution plans, doesn't execute T-SQL.
It does run the stateĀ­ments through the algebrizer , the process outlined earlier that is responsible for verifying the names of database objects. Since the query has not yet been executed, the temporary table does not yet exist. This is the cause of the error.
Running this same bit of code through the Actual execution plan will work perfectly fine.
Hope you got why your temp table approach not worked :) Because you might tried as T-SQL

We can use OPENQUERY
SELECT EmployeeID,CurrentSalary INTO #tempEmp
FROM OPENQUERY(LOCALSERVER,'Exec TestDB.dbo.spEmployee')

Related

Why do I get an invalid column name error when using a temp table twice?

If I run each of these batches separately, it works. However, if they are combined into one script (like what is done when a DACPAC script runs, or putting them both into one tab in SSMS), I get an Invalid column name error on the second insert. Why is that? If I need these to run in one script, do I need to use a different name for the temp table for the second batch? Or am I missing something that would allow me to use the same name?
IF OBJECT_ID('tempdb..#source') IS NOT NULL DROP TABLE #source
SELECT FirstName, LastName INTO #source FROM Musician WHERE 1 = 0; -- set up temp table schema
INSERT INTO #source ( FirstName, LastName )
VALUES
('Geddy', 'Lee'),
('Alex', 'Lifeson')
SELECT * FROM #source
GO
IF OBJECT_ID('tempdb..#source') IS NOT NULL DROP TABLE #source
SELECT [Name], Genre INTO #source FROM Band WHERE 1 = 0; -- set up temp table schema
INSERT INTO #source ( [Name], Genre )
VALUES
('Rush', 'Rock'),
('Ratt', 'Rock')
SELECT * FROM #source
GO
Each batch is parsed independently. So it works when you use GO because they are in different batches.
When you put everything in the same batch, SQL Server parses what it sees, and it is blind to logic like DROP commands hidden behind IF conditionals. Try the following and you'll find the same:
IF (1=0) DROP TABLE IF EXISTS #x; CREATE TABLE #x(i int);
IF (1=1) DROP TABLE IF EXISTS #x; CREATE TABLE #x(j date);
You and I both know that only one of those will ever execute, but the parser spots the redundant table name before it ever gets to execution (or evaluating any conditionals).
This works because, again, each batch is now parsed in isolation:
IF (1=0) DROP TABLE IF EXISTS #x; CREATE TABLE #x(i int);
GO
IF (1=1) DROP TABLE IF EXISTS #x; CREATE TABLE #x(j date);
This will in fact fail even though it passes parsing (highlight and select Parse instead of Execute), so the blindness goes both ways:
IF (1=0) DROP TABLE IF EXISTS #x; CREATE TABLE #x(i int);
GO
IF (1=1) CREATE TABLE #x(j date);
Using go after dropping the tables in both block will do the trick.
IF OBJECT_ID('tempdb..#source') IS NOT NULL DROP TABLE #source
go
SELECT FirstName, LastName INTO #source FROM Musician WHERE 1 = 0; -- set up temp table schema
INSERT INTO #source ( FirstName, LastName )
VALUES
('Geddy', 'Lee'),
('Alex', 'Lifeson')
SELECT * FROM #source
GO
IF OBJECT_ID('tempdb..#source') IS NOT NULL DROP TABLE #source
go
SELECT [Name], Genre INTO #source FROM Band WHERE 1 = 0; -- set up temp table schema
INSERT INTO #source ( [Name], Genre )
VALUES
('Rush', 'Rock'),
('Ratt', 'Rock')
SELECT * FROM #source
GO

SQL - Table Type / passing a table as a paramater

I have a stored procedure that takes in a table as a parameter.
For example: I have a type PartsImport:
CREATE TYPE PartsImport AS TABLE
(
Number_Key varchar(10),
LogDate smalldatetime,
FullName varchar(125),
Descrip varchar(250)
);
Then the stored procedure takes in this param:
#PTable PartsImport ReadOnly
The stored procedure does an insert into a table via a simple select * from #PTable, but now I need to join this table variable with other tables when creating the select statement, but I always get an error message
Must declare the scalar variable "#PPTable"
How do you select an individual column from this #PTable? I tried #PTable.LogDate, but it doesn't like the syntax. Is it possible to use the variable table in a join and select the columns or does it only work with select * ?
You can try using an Alias to refer to your table, instead of the variable name. For example:
SELECT P.LogDate FROM #PTable AS P
try with below example, when you fetch column only from table variable then works fine but when you use in join you must use alias name with table variable name.
CREATE TYPE PartsImport AS TABLE
(
Number_Key varchar(10),
LogDate smalldatetime,
FullName varchar(125),
Descrip varchar(250)
);
create table PartsImportother (col1 varchar(10), col2 varchar(3))
insert into PartsImportother values('1','ads')
Declare #table PartsImport
insert into #table(Number_Key,LogDate,FullName,Descrip) values('1','01-01-2015','aaa','adsfadfa')
-- select [specific column] from [only table variable]
select Number_Key from #table
-- select [specific column] from [table variable with join]
select T.Number_Key from #table as T inner join PartsImportother on T.Number_Key = PartsImportother.col1

INSERT ONLY SPECIFIC COLUMN FROM A STORED PROCEDURE RESULT

I want to know if it is possible to insert to a table from a specific column of result from a stored procedure?
Something like:
declare #temp as table(
id int
)
insert #temp
exec getlistofStudents --returns multiple columns
this is an example only, Thanks for the help..
You can take a 2 step approach. First INSERT INTO a #TempTable, then populate the #TempVariable with another INSERT INTO, selecting the single column.
DECLARE #temp AS TABLE
(
ID int
);
CREATE TABLE #tempTable1
(
Column1 int,
Column2 int
);
INSERT INTO #tempTable1
Exec getlistofStudents
INSERT INTO #temp
SELECT Column1 FROM #tempTable1

SQL Server: Stored Proc input table variable workaround

I'm trying to find a good work around to not being able to use a table variable as an input to a stored procedure. I want to insert a single record into a base table and multiple records into a pivot table. My initial thought process led me to wanting a stored proc with separate inputs for the base table, and a single list input for the pivot table records, i.e.:
create proc insertNewTask (#taskDesc varchar(100), #sTime datetime, #eTime datetime, #items table(itemID int))
as
begin
declare #newTask table(newID int)
insert into tasks(description, sTimeUTC, eTimeUTC)
output inserted.ID into #newTask
values(#taskDesc, #sTime, #eTime)
insert into taskItems(taskID, itemID)
select newID, itemID
from #newTask cross join #items
end
As already stated, the above code won't work because of the table variable input, #items (I believe primarily due to variable scope issues). So, are there any good workarounds to this?
Original Question
I have three tables:
CREATE TABLE items
(
ID int PRIMARY KEY,
name varchar(20),
description varchar(100)
)
CREATE TABLE tasks
(
ID int identity(1,1) PRIMARY KEY,
description varchar(100),
sTimeUTC datetime,
eTimeUTC datetime
)
CREATE TABLE taskItems
(
taskID int,
itemID int,
CONSTRAINT fk_taskItems_taskID FOREIGN KEY (taskID) on tasks(ID),
CONSTRAINT fk_taskItems_itemID FOREIGN KEY (itemID) on items(ID)
)
With some initial item data:
insert into items (ID, name, description)
select 1, 'nails', 'Short piece of metal, with one flat side and one pointed side' union
select 2, 'hammer', 'Can be used to hit things, like nails' union
select 3, 'screws', 'I''m already tired of writing descriptions for simple tools' union
select 4, 'screwdriver', 'If you can''t tell already, this is all fake data' union
select 5, 'AHHHHHH', 'just for good measure'
And I have some code for creating a new task:
declare #taskDes varchar(100), #sTime datetime, #eTime datetime
select #taskDes = 'Assemble a bird house',
#sTime = '2011-01-05 12:00', #eTime = '2011-01-05 14:00'
declare #usedItems table(itemID int)
insert into #usedItems(itemID)
select 1 union
select 2
declare #newTask table(taskID int)
insert into tasks(description, sTimeUTC, eTimeUTC)
output inserted.ID into #newTask
values(#taskDes, #sTime, #eTime)
insert into taskItems(taskID, itemID)
select taskID, itemID
from #newTask
cross join #usedItems
Now, I want a way of simplifying/streamlining the creation of new tasks. My first thought was to use a stored proc, but table variables can't be used as inputs, so it won't work. I think I can do this with a view with an insert trigger, but I'm not sure... Is that my best (or only) option?
I have had great luck using XML to pass data to procedures. You can use OPENXML (Transact-SQL) to parse the XML.
-- You already had an example of #usedItems
-- declared and populated in the question
declare #usedItems table(itemID int)
insert into #usedItems(itemID)
select 1 union
select 2
-- Build some XML, either directly or from a query
-- Here I demonstrate using a query
declare #itemsXML nvarchar(max);
select #itemsXML =
'<Items>'
+ (select itemID from #usedItems as Item for xml auto)
+ '</Items>'
print #itemsXML
-- Pass #itemsXML to the stored procedure as nvarchar(max)
-- Inside the procedure, use OPENXML to turn the XML
-- back into a rows you can work with easily
DECLARE #idoc int
EXEC sp_xml_preparedocument #idoc OUTPUT, #itemsXML
SELECT *
FROM OPENXML (#idoc, '/Items/Item',1)
WITH (itemID int)
EXEC sp_xml_removedocument #idoc
Results
<Items><Item itemID="1"/><Item itemID="2"/></Items>
itemID
-----------
1
2

insert data into several tables

Let us say I have a table (everything is very much simplified):
create table OriginalData (
ItemName NVARCHAR(255) not null
)
And I would like to insert its data (set based!) into two tables which model inheritance
create table Statements (
Id int IDENTITY NOT NULL,
ProposalDateTime DATETIME null
)
create table Items (
StatementFk INT not null,
ItemName NVARCHAR(255) null,
primary key (StatementFk)
)
Statements is the parent table and Items is the child table. I have no problem doing this with one row which involves the use of IDENT_CURRENT but I have no idea how to do this set based (i.e. enter several rows into both tables).
Thanks.
Best wishes,
Christian
Another possible method that would prevent the use of cursors, which is generally not a best practice for SQL, is listed below... It uses the OUTPUT clause to capture the insert results from the one table to be used in the insert to the second table.
Note this example makes one assumption in the fact that I moved your IDENTITY column to the Items table. I believe that would be acceptable, atleast based on your original table layout, since the primary key of that table is the StatementFK column.
Note this example code was tested via SQL 2005...
IF OBJECT_ID('tempdb..#OriginalData') IS NOT NULL
DROP TABLE #OriginalData
IF OBJECT_ID('tempdb..#Statements') IS NOT NULL
DROP TABLE #Statements
IF OBJECT_ID('tempdb..#Items') IS NOT NULL
DROP TABLE #Items
create table #OriginalData
( ItemName NVARCHAR(255) not null )
create table #Statements
( Id int NOT NULL,
ProposalDateTime DATETIME null )
create table #Items
( StatementFk INT IDENTITY not null,
ItemName NVARCHAR(255) null,
primary key (StatementFk) )
INSERT INTO #OriginalData
( ItemName )
SELECT 'Shirt'
UNION ALL SELECT 'Pants'
UNION ALL SELECT 'Socks'
UNION ALL SELECT 'Shoes'
UNION ALL SELECT 'Hat'
DECLARE #myTableVar table
( StatementFk int,
ItemName nvarchar(255) )
INSERT INTO #Items
( ItemName )
OUTPUT INSERTED.StatementFk, INSERTED.ItemName
INTO #myTableVar
SELECT ItemName
FROM #OriginalData
INSERT INTO #Statements
( ID, ProposalDateTime )
SELECT
StatementFK, getdate()
FROM #myTableVar
You will need to write an ETL process to do this. You may want to look into SSIS.
This also can be done with t-sql and possibly temp tables. You may need to store unique key from OriginalTable in Statements table and then when you are inserting Items - join OriginalTable with Statements on that unique key to get the ID.
I don't think you could do it in one chunk but you could certainly do it with a cursor loop
DECLARE #bla char(10)
DECLARE #ID int
DECLARE c1 CURSOR
FOR
SELECT bla
FROM OriginalData
OPEN c1
FETCH NEXT FROM c1
INTO #bla
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO Statements(ProposalDateTime) VALUES('SomeDate')
SET #ID = SCOPE_IDENTITY()
INSERT INTO Items(StateMentFK,ItemNAme) VALUES(#ID,#bla)
FETCH NEXT FROM c1
INTO #bla
END
CLOSE c1
DEALLOCATE c1