INSERT INTO SELECT from UPDATE - sql-server-2005

I need to select some values from a table to be updated, and then update them right away. Furthermore, I need to insert one new record in a table for each updated record. To select records and update I am using a structure like
UPDATE TableA SET SomeField = 1 OUTPUT RecordID FROM TableA WHERE RecordID IN
(
SELECT TOP #Something RecordID FROM TableA
)
Now, for the insert part, I would like to wrap the UPDATE statement into an INSERT INTO SELECT, thus taking advantage of the OUTPUT clause. However, SQL complains when I do
INSERT INTO TableA SELECT ( RecordID , GETDATE() ) FROM
(
UPDATE TableA SET SomeField = 1 OUTPUT RecordID FROM TableA WHERE RecordID IN
(
SELECT TOP #Something RecordID FROM TableA
)
)
Can't I do it all in one statement, even with the OUTPUT clause?

UPDATE TableA SET SomeField = 1
OUTPUT inserted.RecordID, GETDATE() into TableA (RecordID , DT)
FROM TableA
WHERE RecordID IN
(
SELECT TOP #Something RecordID FROM TableA
)
Just not sure - you're trying to insert updated rows again ?

It is posible to use output to insert the updated rows from one table to another:
However I cannot make that syntax you are using to work.
Please check out this link

Of course, you could try something like this:
INSERT INTO TableA (RecordID, Value)
SELECT RecordID, GETDATE()
FROM OPENQUERY(
yourserver,
'UPDATE TableA
SET SomeField = 1
OUTPUT inserted.RecordID
WHERE RecordID IN (SELECT TOP (5) RecordID FROM TableA)'
)
But there's a couple of issues with the approach:
You'd need to create a linked server yourserver.
The 'remote' query wouldn't be very swift.
You'd have hard time replacing TOP (5) with TOP (#Something). Actually you'd most probably have to turn the entire statement into a dynamic query. (That's right, you'd have to put the already dynamic UPDATE inside another dynamic query.)
I expect, with the last issue the one-statement limitation would finally be broken.
So, instead, why not have it like this:
DECLARE #tmpRecords TABLE (RecordID int);
UPDATE TableA
SET SomeField = 1
OUTPUT inserted.RecordID INTO #tmpRecords (RecordID)
WHERE RecordID IN (SELECT TOP (#Something) RecordID FROM TableA);
INSERT INTO TableA (RecordID, SomeDateColumn)
SELECT RecordID, GETDATE()
FROM #tmpRecords;

Related

Insert or update data using cte_results in SQL Server

I have a query having cte with number of columns, I want to insert a record if ID from the results of that query does not exist in table that I am inserting, or if the ID exists I want to update data using that ID.
So far I have tried this:
WITH cte_base as(
SELECT DISTINCT ID, statusID
FROM testtable
)
SELECT *
FROM cte_base
IF EXISTS(SELECT * FROM Newtable WHERE EXISTS (SELECT ID FROM cte_base))
UPDATE newtable
SET statusID = 2
WHERE Newtable.ID = cte_base.ID
ELSE
INSERT INTO newtable(ID, statusID)
SELECT ID, statusID
FROM cte_base
WHERE Newtable.ID <> cte_base.ID
I have to run this query against live data, hence I would like to know if my logic is correct.
Basic merge example based on your provided code.
MERGE INTO NewTable AS T
USING
(
SELECT DISTINCT ID,statusID
FROM testtable
) AS S
ON S.ID = T.ID
WHEN MATCHED THEN SET
T.StatusID = 2
WHEN NOT MATCHED INSERT (ID,statusID)
VALUES (S.ID,S.statusID)
;
What are you trying to do?
EXISTS (SELECT ID FROM cte_base)
If cte_base has any records that will be true every time
That is no different than
SELECT DISTINCT ID, statusID
FROM testtable
And will be true every time if there are any records in testtable

Sql Server Issue During Update

Hello I am little bit confused to see the sql server behaviour on executing the query. According to mine the output should be "Priyanka" ,4
Declare #temp table(
Name Varchar(50),
amount int
)
insert #temp values ('Priyanka' ,10 )
Update #temp
set amount=amount-A.a
from (
select 'Priyanka' as Name,1 as a
union
select 'Priyanka' as Name,5 as a
)A
where [#temp].Name in (A.Name)
select * from #temp
But
the output
Name amount
Priyanka 9
Can any one Please tell me why this is happened.
Standard SQL doesn't support a from clause with update and you'd instead have to write your access to other tables as a direct subquery in the set clause. If you did that, you'd get the error "subquery returned more than one value" and have some idea of the issue.
Unfortunately, the Microsoft extension to SQL that allows a FROM clause also silently ignores the fact that multiple rows may match, uses one of those rows and ignores the others.1
If you're going to use this extension, it's up to you to carefully ensure that you don't have multiple matches to a single row in the target table.
I'd rearrange your query, something like:
Declare #temp table(
Name Varchar(50),
amount int
)
insert #temp values ('Priyanka' ,10 )
;With A as
(
select 'Priyanka' as Name,1 as a
union
select 'Priyanka' as Name,5 as a
)
Update t
set amount=amount-Aa.a
from
#temp t
cross apply
(select SUM(a) as a from A where Name = t.Name) Aa
select * from #temp
Where I use the cross apply to aggregate the data down to a single row per target row.
1Importantly, though, it does support the concept that the effects of an UPDATE are applied "as if" all rows (and columns within them) are updated in parallel. So you don't get that first the update applies using one row and then the second update gets to update an already updated row.
You need to SUM the values of the union entries. Simply UNION the entries it have multiple entries so it may take any one entry and ignore the remains.
For your case the following query will work:
DECLARE #temp TABLE (NAME VARCHAR(50), amount INT)
INSERT #temp
VALUES ('Priyanka', 10)
UPDATE t
SET amount = t.amount - A.a
FROM #temp t
JOIN (
SELECT NAME, SUM(a) AS a FROM (
SELECT 'Priyanka' AS NAME, 1 AS a
UNION
SELECT 'Priyanka' AS NAME, 5 AS a
) c
GROUP BY NAME
) A ON A.NAME = t.NAME
SELECT * FROM #temp

Big Query - Only insert if column value does not exist

Does Big Query support operations like "REPLACE INSERT" or something related to that?
If I run a query like this twice:
INSERT INTO table(column1) VALUES(1)
It'll create a duplicated row, is it possible to insert a row only if a column with the same value does not exist?
Thanks!
Below should make it
#standardSQL
INSERT INTO yourTable(column1)
SELECT value FROM (SELECT 1 AS value)
LEFT JOIN yourTable
ON column1 = value
WHERE column1 IS NULL
Does this work for you?
INSERT INTO table(column1)
WITH s AS (SELECT 1 src)
SELECT src FROM s WHERE NOT EXISTS (
SELECT * FROM table t WHERE t.column1 = s.src
)

the row no in query output

I have a numeric field (say num) in table along with pkey.
select * from mytable order by num
now how I can get the row no in query output of a particular row for which I have pkey.
I'm using sql 2000.
Sounds like you want a row number for each record returned.
In SQL 2000, you can either do this:
SELECT (SELECT COUNT(*) FROM MyTable t2 WHERE t2.num <= t.num) AS RowNo, *
FROM MyTable t
ORDER BY num
which assumes num is unique. If it's not, then you'd have to use the PK field and order by that.
Or, use a temp table (or table var):
CREATE TABLE #Results
(
RowNo INTEGER IDENTITY(1,1),
MyField VARCHAR(10)
)
INSERT #Results
SELECT MyField
FROM MyTable
ORDER BY uum
SELECT * FROM #Results
DROP TABLE #Results
In SQL 2005, there is a ROW_NUMBER() function you could use which makes life a lot easier.
as i understand your question you want to get the number of all rows returned, right?
if so use ##rowcount
As Ada points out, this task became a lot easier in SQL Server 2005....
SELECT whatever, RowNumber from (
SELECT pk
, whatever
, ROW_NUMBER() OVER(ORDER BY num) AS 'RowNumber'
FROM mytable
)
WHERE pk = 23;

Delete records which are considered duplicates based on same value on a column and keep the newest

I would like to delete records which are considered duplicates based on them having the same value in a certain column and keep one which is considered the newest based on InsertedDate in my example below. I would like a solution which doesn't use a cursor but is set based. Goal: delete all duplicates and keep the newest.
The ddl below creates some duplicates. The records which need to be deleted are: John1 & John2 because they have the same ID as John3 and John3 is the newest record.
Also record John5 needs to be deleted because there's another record with ID = 3 and is newer (John6).
Create table dbo.TestTable (ID int, InsertedDate DateTime, Name varchar(50))
Insert into dbo.TestTable Select 1, '07/01/2009', 'John1'
Insert into dbo.TestTable Select 1, '07/02/2009', 'John2'
Insert into dbo.TestTable Select 1, '07/03/2009', 'John3'
Insert into dbo.TestTable Select 2, '07/03/2009', 'John4'
Insert into dbo.TestTable Select 3, '07/05/2009', 'John5'
Insert into dbo.TestTable Select 3, '07/06/2009', 'John6'
Just as an academic exercise:
with cte as (
select *, row_number() over (partition by ID order by InsertedDate desc) as rn
from TestTable)
delete from cte
where rn <> 1;
Most of the time the solution proposed by Sam performs much better.
This works:
delete t
from TestTable t
left join
(
select id, InsertedDate = max(InsertedDate) from TestTable
group by id
) as sub on sub.id = t.id and sub.InsertedDate = t.InsertedDate
where sub.id is null
If you have to deal with ties it gets a tiny bit trickier.