Multiple inserts from multiple WITH/CTE - sql

I have a table like this:
CREATE TABLE mytable
(
col1 character varying(50),
mydate timestamp without time zone
);
I want to insert data to this table, but also I want to store the maximum id from my source:
insert into mytable (select myid, col1, mydate from sourcetable);
I don't have a myid column in mytable, and I can't ask later something like this: select max(myid) from sourcetable because I'm getting a snapshot and the sourcetable is a transactional table (hundreds of new records by second) so I need to get the maximum id from that snapshot
I tried something like this:
with query1 as (select myid, col1, mydate from sourcetable),
query2 as (select max(myid) id from query1)
insert into mytable (select co1, mydate from query1);
update anothertable set value=(select myid from query2) where col2='avalue';
But I get this error:
ERROR: relation "query2" does not exist
LINE 1: update anothertable set value=(select myid from query2) wher...
Is there a way to solve this?

The problem is that you have two queries after the CTEs. Only one. The CTE is connected to the queries. So, just add another CTE. Something like this:
with query1 as (
select myid, col1, mydate
from sourcetable
),
query2 as (
select max(myid) as id
from query1
),
i as (
insert into mytable -- You should really list the columns here
select co1, mydate
from query1
)
update anothertable
set value = (select myid from query2)
where col2 = 'avalue';

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

Update a table in SQL Server 2008 R2 by a column in another table and also need a sum value

I am trying to update a table in SQL Server 2008 R2.
Table1:
id name value1
a 34 3
a 32 2
a - -
c 90 9
Table2:
id
a
expected table1:
id name value1
a 34 3
a 32 2
a - 5
c 90 9
I need to sum all value1 group by id that exists in table2.
My SQL query:
update table1
set value1 = cast(SUM(cast ([value1] as float)) as varchar(50))
GROUP BY id
where name = '-' and id in
(
select distinct id
from table2
)
I got error:
Incorrect syntax near the keyword 'GROUP'.
Any help would be appreciated.
UPDATE
update table1
set value1 = cast(SUM(cast ([value1] as float)) as varchar(50))
where name = '-' and id in
(
select distinct id
from table2
)
GROUP BY id
still :
Incorrect syntax near the keyword 'GROUP'.
You can't use that construct afaik. You need a subquery to calculate your values based on id, and update from that table:
UPDATE table1
SET value1 = SumTable.val
FROM (
SELECT T1.id, cast(SUM(cast (T1.[value1] as float)) as varchar(50)) as val
FROM table1 T1
WHERE T1.id in
(
select distinct T2.id
from table2 T2
)
GROUP BY T1.id
) AS SumTable
WHERE table1.id = SumTable.id
If you just want to return the grouped result, you can do this by running the following
SELECT ID, SUM(Value)
FROM Table1
WHERE ID IN (SELECT ID FROM Table2) GROUP BY ID
If, however, you want to replace the contents of table1, there's no trivial way of doing this in a single operation. You need 'cache' the intermediate result before recreating the original table:
DECLARE #TEMPTABLE TABLE (ID int, Value int);
INSERT INTO #TEMPTABLE SELECT ID, SUM(Value)
FROM Table1
WHERE ID IN (SELECT ID FROM Table2) GROUP BY ID
DROP TABLE Table1
SELECT * INTO Table1 FROM #TempTable
SELECT * FROM TABLE1
(note, that was from your first edit)
If you just want to add additional 'sum' lines to the table, then you should be able to avoid the temp table and instead issue an INSERT INTO statement using the SELECT statement I gave first as a sub-query.
I do think what you're doing is quite strange, however, and you may want to think about what you're doing with your tables.
Your casting back to a VARCHAR is also a little strange - if they're always going to be an integer, keep them as integers. If they're truly VARCHARS then SUM won't always work

INSERT INTO SELECT from UPDATE

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;

t-sql - delete second value only

i would like to run a sql statement that will delete ONLY the second value for example
delete from table1 where condition1
i want this statement to delete ONLY the second value
how can i accomplish this?
i would like to clarify. i have a field called field1 which is an autonumber and and it is a primary key and it increments. i would like to delete the record containing the greater number
You could also employ the ROW_NUMBER() function of SQL server to number each row, and use this number to isolate just the second item for deletion, according to your own custom ordering in the inner query ( over (ORDER BY <myKey> asc) ). This provides a great deal of flexibility.
DELETE a FROM table1
FROM table1 a
JOIN (
select ROW_NUMBER() over (ORDER BY <myKey> asc) as AutoNumber, <myKey> from table1
) b on a.<myKey> = b.<myKey>
WHERE condition1
AND b.AutoNumber = 2
Do you want to delete only the last duplicate, or all but the first?
For all but the first: (Edited to use CTE per #Martin's suggestion.)
with target as (select * from table1 where condition1)
delete from target goner
where exists (select * from target keeper
where keeper.field1 < goner.field1)
In other words, if there is another matching record with a lower field1, delete this record.
EDIT:
To delete only the last:
with target as (select * from table1 where condition1)
delete from target goner
where exists (select * from target keeper
where keeper.field1 < goner.field1)
and not exists (select * from target missing
where missing.field1 > goner.field1)
In other words, if there is another matching record with a lower field1, AND there is no matching record with a higher field1, then we have the highest duplicate, so nuke it.
It's been a while (so my syntax my not quite be right), and this may not be the best solution, but the "academic" answer would be something like:
delete from table1 where condition1
and field1 = (select max(field1) from table1 where condition1)
Try this:
DELETE MyTable
FROM MyTable
LEFT OUTER JOIN (
SELECT MIN(id) as id, Col1, Col2, Col3
FROM MyTable
GROUP BY Col1, Col2, Col3
) as KeepRows ON
MyTable.id= KeepRows.id
WHERE
KeepRows.RowId IS NULL
UPDATE
While this might not be as "pretty" as #Jeffrey's it works. From what I can tell, #Jeffrey's does not. See sql below (Delete replaced with SELECT * for demonstration):
WITH TEMP as
(
SELECT 1 as id,'A' as a,'Z' as b
UNION
SELECT 2,'A','Z'
UNION
SELECT 3,'B','Z'
UNION
SELECT 4,'B','Z'
)
SELECT *
FROM TEMP
LEFT OUTER JOIN (
SELECT MIN(id) as id, a, b
FROM TEMP
GROUP BY a, b
) as KeepRows ON
temp.id= KeepRows.id
WHERE
KeepRows.id IS NULL

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;