Use SELECT result for another query - sql-server

Is there any way other than using a cursor that I can use SELECT results for a subsequent INSERT/UPDATE query?
Something like:
DECLARE #SELECTRESULT;
SELECT Something into #SELECTRESULT
FROM Somewhere
INSERT INTO SomewhereElse (X, XX, XXX)
SELECT Something, GETDATE(), 'XXX'
FROM #SELECTRESULT
UPDATE Somewhere
Set SomethingElse = 'ABC'
WHERE
Something in
(SELECT Something FROM #SELECTRESULT)
The reason is that I have a relatively complex query from multiple tables and I don't want duplicate this code, once for the insert and second time for the update.

You can use a table variable.
Something like
DECLARE #Table TABLE(
Col1 INT
)
INSERT INTO #Table
SELECT Col1
FROM Table
Have a look at
Table Variables In T-SQL
DECLARE #local_variable (Transact-SQL)

Just use a temporary table it's ok for your case :
SELECT Something into #temporary_table FROM Somewhere WHERE blabla

use a temp table.
CREATE TABLE #tempTable
(
Something int NOT NULL,
CurrentDate DateTime NULL,
XXX Varchar(50)
)
Then use your complex query on multiple tables and insert the result set into the tempTable.
Insert into #tempTable
-- Complex Select Query
Just make sure that the columns returned by the selected query match in the order as per the #tempTable structure. Also the number of columns should match.
Once you have #tempTable with the complex data, you can use it multiple number of times for insert and update queries.
INSERT INTO SomewhereElse (X, XX, XXX)
SELECT * from #tempTable
UPDATE Somewhere
Set SomethingElse = 'ABC'
WHERE
Something in (SELECT Something FROM #tempTable)

DECLARE #SELECTRESULT table(Something nvarchar(50)) --the data that you could reuse.
insert into #SELECTRESULT(Something)
SELECT Something
FROM Somewhere
INSERT INTO SomewhereElse (X, XX, XXX)
SELECT Something, GETDATE(), 'XXX'
FROM #SELECTRESULT
UPDATE Somewhere
Set SomethingElse = 'ABC'
WHERE Something in
(SELECT Something FROM #SELECTRESULT)

Related

Checking whether value exists in results of a stored procedure

I have a stored procedure which returns a list of IDs for a particular set of generators I want to be able to then use the results of this stored procedure as part of another query.
Can I write a query like:
select * from table where id in (exec dbo.storedprocedurename)
Using table variable and JOIN you can achieve this. Store the procedure result into the table.
DECLARE #ProcOutput TABLE (Id INT);
INSERT INTO #ProcOutput (Id)
EXEC [dbo].[storedprocedurename]
SELECT T.*
FROM Table T
JOIN #ProcOutput O ON O.Id = T.Id
If the procedure returns multiple entries, according to the output you can re-design the table's schema.
If your output of procedure is 2 columns then you may try this:
INSERT INTO MyTable
(
Col1,
Col2
)
EXEC [dbo].[storedprocedurename]
GO
SELECT * FROM TABLE WHERE ID IN (SELECT Col1 from Mytable)

Insert Into Selected Table name

I would like to do something like this in SQL Server:
INSERT INTO(Here I have SELECT which return Table name) (col1, col2, col3)
VALUES (a, b, c)
I build table name by using the Select statement and I would like to insert some values into this table.
Is it possible to do?
you can do with dynamic SQL
declare #table varchar(100),#sqlst varchar(max)
select #table=tablename from tables
set #sqlst ='insert into '+ #table +'(1,2,3) values(''a'',''b'',''c'')'
exec(#sqlst)
You can do this via a dynamic query like below
DECLARE #Q nvarchar(MAX)
SELECT #Q=N'INSERT INTO '+ tablename +N' (1,2,3) values(''a'',''b'',''c'')' FROM SomeTable
EXEC(#Q)
Please note that since alphanumeric values like a,b,c need to be inserted with single quotes, you'll have to escape the single quotes by another quote

How to avoid bulk data duplicate values when insert in to a table in SQL Server 2012

The problem im trying to solve is about avoiding duplicate data getting into my table. I'm using xml to send bulk data to a stored procedure. The procedure I wrote works with 100, 200 records. But when it comes to 20000 of them there is a time out exception.
This is the stored procedure:
DECLARE #TEMP TABLE (Page_No varchar(MAX))
DECLARE #TEMP2 TABLE (Page_No varchar(MAX))
INSERT INTO #TEMP(Page_No)
SELECT
CAST(CC.query('data(PageId)') AS NVARCHAR(MAX)) AS Page_No
FROM
#XML.nodes('DocumentElement/CusipsFile') AS tt(CC)
INSERT INTO #TEMP2(Page_No)
SELECT Page_No
FROM tbl_Cusips_Pages
INSERT INTO tbl_Cusips_Pages(Page_No, Download_Status)
SELECT Page_No, 'False'
FROM #TEMP
WHERE Page_No NOT IN (SELECT Page_No FROM #TEMP
INTERSECT
SELECT Page_No FROM #TEMP2)
How can I solve this? Is there a better way to write this procedure?
As was already suggested, NVARCHAR(MAX) column/variable is very slow and has limited options. If you can change it, it would help a lot.
MERGE tbl_Cusips_Pages
USING (
SELECT
CAST(CC.query('data(PageId)') AS NVARCHAR(4000))
FROM
#XML.nodes('DocumentElement/CusipsFile') AS tt(CC)
) AS source (Page_No)
ON tbl_Cusips_Pages.Page_No = source.Page_No
WHEN NOT MATCHED BY TARGET
THEN INSERT (Page_No, Download_Status)
VALUES (source.Page_No, 'false')
Anyway, your query is not that bad either, just put the queries directly into the third one (TEMP2 one for sure) instead of inserting the data into the table variables. Table variables are quite slow in comparison.
Replace last INSERT Statement with following Script, I have replace IN Clause With NOT EXISTS that may help you for better performance.
DECLARE #CommanPageNo TABLE (Page_No varchar(MAX))
INSERT INTO #CommanPageNo SELECT Page_No FROM #TEMP
INTERSECT
SELECT Page_No FROM #TEMP2
INSERT INTO tbl_Cusips_Pages(Page_No, Download_Status)
SELECT Page_No, 'False'
FROM #TEMP
WHERE NOT EXISTS (SELECT 1 FROM #CommanPageNo WHERE Page_No=#CommanPageNo.Page_No)

SQL Server: is it possible to get recently inserted identity column value without table variable

Let's say I have a table
my_table(id int identity(1,1) not null primary key, data varchar(100))
I want to write a procedure that inserts a new row into that table and returns id.
I tried
DECLARE #new_id INT;
SELECT #new_id = id FROM
(
INSERT INTO my_table(data) OUTPUT inserted.id VALUES ('test')
) as NewVal(id)
That code doesn't work (I got "A nested INSERT, UPDATE, DELETE, or MERGE statement is not allowed in a SELECT statement that is not the immediate source of rows for an INSERT statement."). However, if I use a table variable, I can do
DECLARE #new_id INT;
DECLARE #tmp_table TABLE(int id);
INSERT INTO #tmp_table
SELECT id FROM
(
INSERT INTO my_table(data) OUTPUT inserted.id VALUES ('test')
) as NewVal(id);
// OR
INSERT INTO my_table(data) OUTPUT inserted.id INTO #tmp_table VALUES ('test') ;
SELECT #new_id = id FROM #tmp_table;
Is it possible to achieve the same functionality without using table variable ?
UPDATE
Thanks for quick responses, +1 to everyone for solution with SCOPE_IDENTITY.
That's probably my fault, I should have asked the question clearly - I do use MERGE (an example would be much longer, so I posted INSERT instead) , not INSERT so SCOPE_IDENTITY doesn't really work for me.
A bit shorter version than nesting in a insert statement is using output...into.
declare #tmp_table table(actiontaken nvarchar(10), id int);
merge my_table
using (values ('test')) as S(data)
on 0=1
when not matched then
insert (data) values (S.data)
output $action, inserted.id into #tmp_table;
I do believe that you should use a table variable from the merge. The output may contain more than one row.
Yes, you can just return SCOPE_IDENTITY after the insert (this is safer than ##IDENTITY due to the scoping differences).
i.e.
INSERT my_table (data) VALUES ('test')
SELECT SCOPE_IDENTITY()
SELECT SCOPE_IDENTITY() will get the last inserted identity value in the scope.
If you use
select ##identity
you will get the last value entered into the identity column from anywhere.
If you want the value entered into the column from the script that just ran, you should use
select SCOPE_IDENTITY()
If you just want the last value inserted into the identity column for a given table from any statement in any session, you should use
select IDENT_CURRENT('tablename')
select ##identity or select SCOPE_IDENTITY() will return the value you're looking for

SELECT INTO a table variable in T-SQL

Got a complex SELECT query, from which I would like to insert all rows into a table variable, but T-SQL doesn't allow it.
Along the same lines, you cannot use a table variable with SELECT INTO or INSERT EXEC queries.
http://odetocode.com/Articles/365.aspx
Short example:
declare #userData TABLE(
name varchar(30) NOT NULL,
oldlocation varchar(30) NOT NULL
)
SELECT name, location
INTO #userData
FROM myTable
INNER JOIN otherTable ON ...
WHERE age > 30
The data in the table variable would be later used to insert/update it back into different tables (mostly copy of the same data with minor updates). The goal of this would be to simply make the script a bit more readable and more easily customisable than doing the SELECT INTO directly into the right tables.
Performance is not an issue, as the rowcount is fairly small and it's only manually run when needed.
...or just tell me if I'm doing it all wrong.
Try something like this:
DECLARE #userData TABLE(
name varchar(30) NOT NULL,
oldlocation varchar(30) NOT NULL
);
INSERT INTO #userData (name, oldlocation)
SELECT name, location FROM myTable
INNER JOIN otherTable ON ...
WHERE age > 30;
The purpose of SELECT INTO is (per the docs, my emphasis)
To create a new table from values in another table
But you already have a target table! So what you want is
The INSERT statement adds one or more new rows to a table
You can specify the data values in the
following ways:
...
By using a SELECT subquery to specify
the data values for one or more rows,
such as:
INSERT INTO MyTable
(PriKey, Description)
SELECT ForeignKey, Description
FROM SomeView
And in this syntax, it's allowed for MyTable to be a table variable.
You can also use common table expressions to store temporary datasets. They are more elegant and adhoc friendly:
WITH userData (name, oldlocation)
AS
(
SELECT name, location
FROM myTable INNER JOIN
otherTable ON ...
WHERE age>30
)
SELECT *
FROM userData -- you can also reuse the recordset in subqueries and joins
You could try using temporary tables...if you are not doing it from an application. (It may be ok to run this manually)
SELECT name, location INTO #userData FROM myTable
INNER JOIN otherTable ON ...
WHERE age>30
You skip the effort to declare the table that way...
Helps for adhoc queries...This creates a local temp table which wont be visible to other sessions unless you are in the same session. Maybe a problem if you are running query from an app.
if you require it to running on an app, use variables declared this way :
DECLARE #userData TABLE(
name varchar(30) NOT NULL,
oldlocation varchar(30) NOT NULL
);
INSERT INTO #userData
SELECT name, location FROM myTable
INNER JOIN otherTable ON ...
WHERE age > 30;
Edit: as many of you mentioned updated visibility to session from connection. Creating temp tables is not an option for web applications, as sessions can be reused, stick to temp variables in those cases
Try to use INSERT instead of SELECT INTO:
DECLARE #UserData TABLE(
name varchar(30) NOT NULL,
oldlocation varchar(30) NOT NULL
)
INSERT #UserData
SELECT name, oldlocation
First create a temp table :
Step 1:
create table #tblOm_Temp (
Name varchar(100),
Age Int ,
RollNumber bigint
)
**Step 2: ** Insert Some value in Temp table .
insert into #tblom_temp values('Om Pandey',102,1347)
Step 3: Declare a table Variable to hold temp table data.
declare #tblOm_Variable table(
Name Varchar(100),
Age int,
RollNumber bigint
)
Step 4: select value from temp table and insert into table variable.
insert into #tblOm_Variable select * from #tblom_temp
Finally value is inserted from a temp table to Table variable
Step 5: Can Check inserted value in table variable.
select * from #tblOm_Variable
OK, Now with enough effort i am able to insert into #table using the below :
INSERT #TempWithheldTable SELECT
a.SuspendedReason,
a.SuspendedNotes,
a.SuspendedBy ,
a.ReasonCode FROM OPENROWSET( BULK 'C:\DataBases\WithHeld.csv', FORMATFILE =
N'C:\DataBases\Format.txt',
ERRORFILE=N'C:\Temp\MovieLensRatings.txt'
) AS a;
The main thing here is selecting columns to insert .
One reason to use SELECT INTO is that it allows you to use IDENTITY:
SELECT IDENTITY(INT,1,1) AS Id, name
INTO #MyTable
FROM (SELECT name FROM AnotherTable) AS t
This would not work with a table variable, which is too bad...

Resources