This question already has answers here:
Is it possible to for SQL Output clause to return a column not being inserted?
(2 answers)
Closed 2 years ago.
Microsoft's OUTPUT Clause documentation says that you are allowed to use from_table_name in the OUTPUT clause's column name.
There are two examples of this:
Using OUTPUT INTO with from_table_name in an UPDATE statement
Using OUTPUT INTO with from_table_name in a DELETE statement
Is it possible to also use it in an INSERT statement?
INSERT INTO T ( [Name] )
OUTPUT S.Code, inserted.Id INTO #TMP -- The multi-part identifier "S.Code" could not be bound.
SELECT [Name] FROM S;
Failing example using table variables
-- A table to insert into.
DECLARE #Item TABLE (
[Id] [int] IDENTITY(1,1),
[Name] varchar(100)
);
-- A table variable to store inserted Ids and related Codes
DECLARE #T TABLE (
Code varchar(10),
ItemId int
);
-- Insert some new items
WITH S ([Name], Code) AS (
SELECT 'First', 'foo'
UNION ALL SELECT 'Second', 'bar'
-- Etc.
)
INSERT INTO #Item ( [Name] )
OUTPUT S.Code, inserted.Id INTO #T -- The multi-part identifier "S.Code" could not be bound.
SELECT [Name] FROM S;
No, because an INSERT doesn't have a FROM; it has a set of values that are prepared either by the VALUES keyword, or from a query (and even though that query has a FROM, you should conceive that it's already been run and turned into a block of values by the time the insert is done; there is no s.code any more)
If you want to output something from the table that drove the insert you'll need to use a merge statement that never matches any records (so it's only inserting) instead, or perhaps insert all your data into #tmp and then insert from #tmp into the real table - #tmp will thus still be the record of rows that were inserted, it's just that it was created to drive the insert rather than as a consequence of it (caveats that it wouldn't contain calculated columns)
Related
This question already has answers here:
Is it possible to for SQL Output clause to return a column not being inserted?
(2 answers)
Closed 11 months ago.
I have a reference TableA with a single column called [SomeID]:
SomeID
ABC
DEF
GHI
KLM
I have TableB can be:
CREATE TABLE TableB([ID] BIGINT, [Name] NVARCHAR(50))
[ID] is the primary key and is auto-increment.
I want to create a new record in TableB for each record of TableA.
So we do this:
DECLARE #OuputTable TABLE([ID] BIGINT, [SomeID] NVARCHAR(50))
INSERT INTO TableB([Name])
OUTPUT INSERTED.[ID], 'Need Associated SomeID From TableA Here' INTO #OutputTable
SELECT 'ZZZZZZ' -- Edited this line to remove some possible confusion.
FROM TableA
SELECT *
FROM
#OuputTable
How would I be able to place the associated [SomeID] value for each of the created record in #OuputTable without using a loop?
You can try to use MERGE INTO which might allow you get source data value in OUTPUT
MERGE INTO TableB AS dest
USING TableA AS sou ON 1=0
WHEN NOT MATCHED
THEN INSERT ([Name])
VALUES (sou.[SomeID])
OUTPUT INSERTED.[ID], sou.SomeID
INTO #OutputTable (ID, SomeID);
sqlfiddle
I have a MEMBER table and NOTIFICATION table. On client side, I list all of the records in MEMBER table and there is a points column and this is shown as text input. So after I change the values for some members, I can click save button and this will update the records in my MEMBER table that's all right,
But the thing I want to accomplish is for every record whose points value has changed I want to INSERT a record in my notifications table.
I couldn't think of anything, how can I approach to this problem?
For notifications I made 3 tables by following the article in here
Use the output clause instead of trigger, they are bad.
You need the condition "where data_old <> data_new" case if you updated a column with the same value, SQL Server marked it as changed, even if the value hasn't changed
create table #example (id int identity(1,1) not null, data nvarchar(max));
insert into #example (data) values ('value 1'),('value 2'), ('value 3');
create table #audit (id int, data_old nvarchar(max), data_new nvarchar(max), [When] datetime not null default (getdate()));
insert into #audit (id, data_old, data_new)
select id, data_old, data_new
from (
update #example
set data = 'value changed'
output inserted.id, deleted.data as data_old, inserted.data as data_new
where id = 2
)changed (id, data_old, data_new)
where data_old <> data_new
select * from #audit
will result with this in #audit :
You have described what a trigger does.
create trigger trig_member_insert on members after update
as
begin
insert into notifications ( . . . )
select . . ., i.points as new_points u.points as old_points -- what you want to insert
from inserted i join
updated u
on i.member_id = u.member_id
where u.points <> i.points
end;
Storing something called "points" as a string seems like a very poor choice. It sounds like a number.
How can I insert data into the table from the finished procedure, which was created using other scripts (data are on the rows in the results). This solutions was necessarily because I must concatenate coordinates.
One of the finishing step is:
select concat ('insert into table_shop ([IU], [ODD]) values ', data1)as PasteDat
from #tmp_07
In value data1 I have upload data.
When finished scripts I have result a lot of rows.
For example:
insert into table_shop ([IU], [ODD]) values ('A0001', 'D08')
insert into table_shop ([IU], [ODD]) values ('Agw44', 'D10')
insert into table_shop ([IU], [ODD]) values ('A5888', 'D18')
.
.
.
Now what I do is copying rows and paste on the other new query. Is there a more elegant way to do it in bulk?
Hope this helps
Use AdventureWorks2012
GO
Create Table #temp --table into which we need to insert
(
[DepartmentID] int,
[Name] varchar(50)
)
GO
Create PROCEDURE SP_ResultSet --SP which returns a result set
as
Select [DepartmentID]
,[Name]
from [HumanResources].[Department]
GO
Insert into #temp EXEC SP_ResultSet -- serves the purpose
GO
Select * from #temp order by [DepartmentID]
I have a list of values such as
1,2,3,4...
that will be passed into my SQL query.
I need to have these values stored in a table variable. So essentially I need something like this:
declare #t (num int)
insert into #t values (1),(2),(3),(4)...
Is it possible to do that formatting in SQL Server? (turning 1,2,3,4... into (1),(2),(3),(4)...
Note: I can not change what those values look like before they get to my SQL script; I'm stuck with that list. also it may not always be 4 values; it could 1 or more.
Edit to show what values look like: under normal circumstances, this is how it would work:
select t.pk
from a_table t
where t.pk in (#place_holder#)
#placeholder# is just a literal place holder. when some one would run the report, #placeholder# is replaced with the literal values from the filter of that report:
select t.pk
from a_table t
where t.pk in (1,2,3,4) -- or whatever the user selects
t.pk is an int
note: doing
declare #t as table (
num int
)
insert into #t values (#Placeholder#)
does not work.
Your description is a bit ridicuolus, but you might give this a try:
Whatever you mean with this
I see what your trying to say; but if I type out '#placeholder#' in the script, I'll end up with '1','2','3','4' and not '1,2,3,4'
I assume this is a string with numbers, each number between single qoutes, separated with a comma:
DECLARE #passedIn VARCHAR(100)='''1'',''2'',''3'',''4'',''5'',''6'',''7''';
SELECT #passedIn; -->: '1','2','3','4','5','6','7'
Now the variable #passedIn holds exactly what you are talking about
I'll use a dynamic SQL-Statement to insert this in a temp-table (declared table variable would not work here...)
CREATE TABLE #tmpTable(ID INT);
DECLARE #cmd VARCHAR(MAX)=
'INSERT INTO #tmpTable(ID) VALUES (' + REPLACE(SUBSTRING(#passedIn,2,LEN(#passedIn)-2),''',''','),(') + ');';
EXEC (#cmd);
SELECT * FROM #tmpTable;
GO
DROP TABLE #tmpTable;
UPDATE 1: no dynamic SQL necessary, all ad-hoc...
You can get the list of numbers as derived table in a CTE easily.
This can be used in a following statement like WHERE SomeID IN(SELECT ID FROM MyIDs) (similar to this: dynamic IN section )
WITH MyIDs(ID) AS
(
SELECT A.B.value('.','int') AS ID
FROM
(
SELECT CAST('<x>' + REPLACE(SUBSTRING(#passedIn,2,LEN(#passedIn)-2),''',''','</x><x>') + '</x>' AS XML) AS AsXml
) as tbl
CROSS APPLY tbl.AsXml.nodes('/x') AS A(B)
)
SELECT * FROM MyIDs
UPDATE 2:
And to answer your question exactly:
With this following the CTE
insert into #t(num)
SELECT ID FROM MyIDs
... you would actually get your declared table variable filled - if you need it later...
We probably all know SCOPE_IDENTITY() to retrieve the identity generated by a single insert. Currently I'm in the need of some kind of magic variable or function to retrieve all the rows generated by a statement, eg:
INSERT INTO [dbo].[myMagicTable]
(
[name]
)
SELECT [name]
FROM [dbo].[myMagicSource]
WHERE /* some weird where-clauses with several subselects ... */;
INSERT INTO [dbo].[myMagicBackupTable]
(
[id],
[name]
)
SELECT
[id],
[name]
FROM ???
An insert trigger is no option, as this will perform a single insert which is a problem for a batch of 10.000 rows...
So, is there any way to achieve this?
We are using mssql2005<
For SQL Server 2005+, you can use the OUTPUT clause.
DECLARE #InsertedIDs table(ID int);
INSERT INTO [dbo].[myMagicTable]
OUTPUT INSERTED.ID
INTO #InsertedIDs
SELECT ...
You could define a temporary table (possibly a table variable) and make use of the OUTPUT clause on your INSERT (you can make use of the Inserted pseudo-table, like in a trigger):
DECLARE #NewIDs TABLE (MagicID INT, Name VARCHAR(50))
INSERT INTO [dbo].[myMagicTable]([name])
OUTPUT Inserted.MagicID, Inserted.Name INTO #NewIDs(MagicID, Name)
SELECT [name]
FROM [dbo].[myMagicSource]
WHERE /
and then use that table variable after the INSERT:
INSERT INTO
[dbo].[myMagicBackupTable]([id], [name])
SELECT MagicID, [name]
FROM #NewIDs
and go from there.