Output Clause Explained - sql-server

Please explain to me the SQL Server output clause.

Do some examples help? The below all output the result to the client but you can also OUTPUT INTO a #table_variable (or a standard table under certain conditions)
create table T
(
id int identity(1,1),
c char(1)
)
insert into T(c)
OUTPUT inserted.* /*Output Inserted Rows - shows the ids that were allocated*/
values ('A'),('B'),('C')
Returns
id c
----------- ----
1 A
2 B
3 C
.
UPDATE T
SET c = CHAR(ASCII(c)+1)
/*Output before and after versions of each row*/
OUTPUT deleted.*, inserted.*
WHERE id IN (2,3)
Returns
id c id c
----------- ---- ----------- ----
2 B 2 C
3 C 3 D
.
DELETE
FROM T
/*Output the row(s) that were deleted*/
OUTPUT deleted.*
WHERE DATEPART(second, getdate())%id = 0
Returns (for example)
id c
----------- ----
1 A
Edit:
In response to comment some examples showing how OUTPUT can be used to insert to a table.
CREATE TABLE #T2
(
id UNIQUEIDENTIFIER DEFAULT NEWSEQUENTIALID(),
c CHAR(1)
)
DECLARE #inserted TABLE
(
id UNIQUEIDENTIFIER,
c CHAR(1)
)
INSERT INTO #T2(c)
OUTPUT inserted.id, inserted.c
INTO #inserted
VALUES ('A')
If you are on SQL Server 2008 you can use composable DML
INSERT INTO #inserted
SELECT I.id, I.c
FROM
(
INSERT INTO #T2(c)
OUTPUT inserted.id, inserted.c
VALUES ('B'),('C')
) AS I
WHERE c <> 'C' --Only add rows of interest to #inserted table
But you will get an error message if the insert target participates in a PK/FK relationship. If you encounter this problem you can also use this pattern.
INSERT INTO #inserted
EXEC sp_executesql N'
INSERT INTO #T2(c)
OUTPUT inserted.id, inserted.c
VALUES (''D''),(''E'') '

It could be stated as
How do I find out what rows were deleted, inserted or updated?
You can using some fancy trigger code or a separate SELECT, but the OUTPUT clause make it effortless. The SELECT becomes part of the actual DELETE, INSERT or UPDATE

The OUTPUT clause allows you to combine an INSERT or UPDATE with a SELECT.
You can OUTPUT a list of fields, and the query will return one row for each row affected by the INSERT / UPDATE.

Related

How to find other than current value in SQL Server?

In SQL Server, how can I get data from a column other than specified data.
For example, I have a column with data "MySQL,Server,Database" in single row.
Now I want to find if there is any other value than MySQL in that column.
I tried by using Not Like but didn't succeed.
For example TableA :
id | Code
---+---------------------------
1 | mysql,sqlserver,database
2 | mysql
3 | sqlserver,database
4 | mysql,mysql
Here, I want to find if the column has data other than "mysql" or not, like id:1 has data other than "mysql" but id:2 have "mysql" but not other than "mysql".
Finally if I want to return the null or blank value if there no any data other than "mysql".
Code I used so far :
select code from tableA where code not like '%mysql%'
It helps if you can provide some data and some code. This works (as far as I understand the question):
CREATE TABLE #x (object_type varchar(50))
INSERT #x (object_type) VALUES ('MySQL'), ('Server'), ('Database')
SELECT * FROM #x WHERE object_type <> 'MySQL'
Base on the updated question, I think you're looking for:
CREATE TABLE #x (id int identity(1, 1), code varchar(50))
INSERT #x (code) VALUES ('mysql,sqlserver,database'), ('mysql'), ('sqlserver,database'), ('mysql,mysql')
SELECT *
FROM #x
WHERE id IN (
SELECT id
FROM #x
CROSS APPLY string_split(code, ',')
WHERE value <> 'mysql'
)
However, as #Eric Brandt asked above, it's not clear whether you want to select row id = 4.
Note STRING_SPLIT is only available for SQL Server 2016 or later. if you are using a earlier version, do a search, there are lots of similar implementation
declare #table table
(
id int identity,
Code varchar(30)
)
insert into #table select 'mysql,sqlserver,database'
insert into #table select 'mysql'
insert into #table select 'sqlserver,database'
insert into #table select 'mysql,mysql'
insert into #table select ''
insert into #table select NULL
select *
from #table t
where t.Code is null
or exists
(
select *
from string_split(t.Code, ',')
where value <> 'mysql'
)
/* RESULT
1 mysql,sqlserver,database
3 sqlserver,database
5
6 NULL
*/

How to Show a particular row first from a select query

I have a query results like below
name id
a 2
b 3
c 7
h 9
i 1
i need to show the results like below
Expected Result
name id
c 7
a 2
b 3
h 9
i 1
The id field is Primarykey so based on that i want to show this
so far i tried with order by but it only give the option to order like decenting or acenting.
Please help me to do this
I had done something like below
create procedure proc1
#id int;
begin
select name,id from tablname order by id
end
I had also tried like but it also fails . Please help me to solve this
Try this:
CREATE PROCEDURE proc1 (#id int)
AS
SELECT name,id
FROM tablname
ORDER BY CASE WHEN id=#id THEN 0 ELSE id END
Note: This will work assuming the values of your id columns are always greater then 0.
I tried this and it gives exactly what is your required output.
declare #name varchar(10)
set #name = 'c'
create table #temp (id int ,name varchar(10))
insert into #temp(id,name) values(1,'i')
insert into #temp(id,name) values(2,'a')
insert into #temp(id,name) values(3,'b')
insert into #temp(id,name) values(7,'c')
insert into #temp(id,name) values(9,'h')
Select name,id from #temp ORDER BY CASE WHEN name=#name THEN '' ELSE name END
Drop table #temp

How to get the just inserted row in SQL Server stored procedure (without using trigger)?

I have stored procedures that inserts/updates records in some tables. Some columns of those tables have default values or auto-increment. Here's what I have:
ALTER PROCEDURE [dbo].[Usp___NewExpense]
#iCampaignID int,
#iCategory int,
#iUserID int,
#dDate Date,
#iAmountInINR int,
#strComments VarChar(200)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO dbo.Tbl_Expenses(iCampaignID, iCategory, dDate, iAmountInINR, strComments)
VALUES (#iCampaignID, #iCategory, #dDate, #iAmountInINR, #strComments);
-- How to get the record inserted using the above statement here without using triggers
-- or another select statement, so that I can assign values to the following variables?
Declare #justInsertedValue1 type1;
Declare #justInsertedValue2 type2;
Declare #justInsertedValue3 type3;
INSERT INTO dbo.Tbl_SomeOtherTable(col1, col2, col3)
VALUES (justInsertedValue1, justInsertedValue2, justInsertedValue3);
END
GO
Tbl_Expenses has about 9 columns in which two have default values and two have auto-increment set. How can I get the just inserted record just below my INSERT statement?
I know that I can use SCOPE_IDENTITY() and then a SELECT, but a query would probably make it inefficient (am I right?).
(By getting the just inserted record, I mean values of all fields of the just inserted record)
Edit: I haven't specified values for all the fields in my INSERT statement. I want to get those values inserted automatically by SQL Server due to DEFAULT/AUTO INCREMENT constraints also.
You can use the OUTPUT clause. You can even combine both inserts into one composite:
create table T1 (ID int IDENTITY(1,1) not null,ColA varchar(10) not null)
create table T2 (ID int IDENTITY(1,1) not null,T1ID int not null,ColB varchar(10) not null)
--Look ma! no local variables at all
insert into T2 (T1ID,ColB)
select t1.ID,'def'
from (
insert into T1(ColA)
output inserted.ID
values ('abc')
) t1
select * from T1
select * from T2
Results:
ID ColA
----------- ----------
1 abc
ID T1ID ColB
----------- ----------- ----------
1 1 def

tsql return identity values when inserting multiple records into a view

I have a situation where I need to insert multiple records/batch insert into a view which has instead of trigger. How can I retrieve the inserted identity values? I tried using the OUTPUT clause to retrieve the Id from the Inserted table but it always returns null.
Using this setup.
create table InsteadOf
(
ID int identity primary key,
Name varchar(10) not null
)
go
create view v_InsteadOf
as
select ID, Name
from InsteadOf
go
create trigger tr_InsteadOf on InsteadOf instead of insert
as
begin
insert into InsteadOf(Name)
select Name
from inserted
end
The statement
insert into v_InsteadOf(Name)
output inserted.*
select 'Name1' union all
select 'Name2'
Will give you an error.
Msg 334, Level 16, State 1, Line 4 The target table 'InsteadOf' of the
DML statement cannot have any enabled triggers if the statement
contains an OUTPUT clause without INTO clause.
Using an INTO clause with the insert instead.
declare #IDs table(ID int, Name varchar(10))
insert into v_InsteadOf(Name)
output inserted.* into #IDs
select 'Name1' union all
select 'Name2'
select *
from #IDs
Gives you 0 as a value not null.
ID Name
----------- ----------
0 Name1
0 Name2
You can put the output clause in the trigger.
create trigger tr_InsteadOf on InsteadOf instead of insert
as
begin
insert into InsteadOf(Name)
output inserted.*
select Name
from inserted
end
And the output will be generated for you when you do the insert.
insert into v_InsteadOf(Name)
select 'Name1' union all
select 'Name2'
Result:
ID Name
----------- ----------
1 Name1
2 Name2
Update:
To capture the output from the insert statement you can use insert into ... exec (...)
declare #T table
(
ID int,
Name varchar(10)
)
insert into #T
exec
(
'insert into v_InsteadOf(Name)
values (''Name1''),(''Name2'')'
)

SQL Server Merge statement

I am doing merge statement in my stored procedure. I need to count the rows during updates and inserts. If i use a common variable to get the updated rows (for both update and insert) how i can differ, this is the count which i got from update and this is the count which i got from insert. Please give me a better way
You can create a table variable to hold the action type then OUTPUT the pseudo $action column to it.
Example
/*Table to use as Merge Target*/
DECLARE #A TABLE (
[id] [int] NOT NULL PRIMARY KEY CLUSTERED,
[C] [varchar](200) NOT NULL)
/*Insert some initial data to be updated*/
INSERT INTO #A
SELECT 1, 'A' UNION ALL SELECT 2, 'B'
/*Table to hold actions*/
DECLARE #Actions TABLE(act CHAR(6))
/*Do the Merge*/
MERGE #A AS target
USING (VALUES (1, '#a'),( 2, '#b'),(3, 'C'),(4, 'D'),(5, 'E')) AS source (id, C)
ON (target.id = source.id)
WHEN MATCHED THEN
UPDATE SET C = source.C
WHEN NOT MATCHED THEN
INSERT (id, C)
VALUES (source.id, source.C)
OUTPUT $action INTO #Actions;
/*Check the result*/
SELECT act, COUNT(*) AS Cnt
FROM #Actions
GROUP BY act
Returns
act Cnt
------ -----------
INSERT 3
UPDATE 2

Resources