I have a stored procedure which inserts records into a table using values from my table variable. (The table variable is sent to SQL from ASP.NET) It works perfect and looks like this...
CREATE PROCEDURE sp_SaveResponses
(
#TableVariable SaveResponsesTableType READONLY
)
AS
BEGIN
INSERT INTO tbl_Responses
(
assessmentid, questionid, answerid
)
SELECT assessmentid, questionid, answerid
FROM #TableVariable
END
The above inserts one record into tbl_Responses for every row in #TableVariable.
The Problem
Instead of INSERT, I would like to perform an UPDATE, but I can't get the syntax right.
Thanks for any help...!
UPDATE
With some helpful hints, I was able to resolve this below...
You could try this (I haven't tested it) -
CREATE PROCEDURE sp_SaveResponses
(
#TableVariable SaveResponsesTableType READONLY
)
AS
BEGIN
UPDATE tbl_Responses set questionid = #TableVariable.questionid
FROM #TableVariable
WHERE #TableVariable.assessmentid = tbl_Response.assessmentid
END
Depending on what the join is between the table variable and the table that needs to be updated:
CREATE PROCEDURE sp_SaveResponses
(
#TableVariable SaveResponsesTableType READONLY
)
AS
BEGIN
UPDATE
tbl_Responses
SET
questionid = #TableVariable.questionid
FROM
#TableVariable T1
JOIN tbl_Responses T2 ON T1.assessmentid = T2.assessmentID
END
Thanks to #ipr1010 and #cob666 whose answers led me in the right direction... Here is the solution.
UPDATE tbl_Responses SET answerid = T1.answerid
FROM #TableVariable T1
WHERE tbl_Responses.assessmentid = T1.assessmentid AND tbl_Responses.questionid = T1.questionid
Naming #TableVariable T1 resolved the "must declare scalar variable..." issue.
I also needed to update my WHERE clause or all values were updated with the first value in #TableVariable.
I wish I could vote you guys up but apparently my street cred is too weak!
Related
Description what I am trying to do:
I have 2 environments one has data (X) second one has no data (Y).
I have done procedure which has input parameter P_TableName. It should check if in this table is any data and IF There is then we will take data to Y environment.
So Mostly it works but I have problem with one freaking simple thing ( I have not much experience in TD but in Oracle it would be a 10seconds).
I need to pass select count(*) from X to variable how to do that?.
I was trying by SET VAR = SELECT...
INSERT INTO VAR SELECT...
I was trying to make a variable for statement which is directly executing
SET v_sql_stmt = 'INSERT INTO ' || VAR|| ' SELECT COUNT(*) FROM ' || P_TableName;
CALL DBC.SYSEXECSQL(v_sql_stmt);
It's probably really simple thing but I can't find good solution for that. Please help
You'll have to open a cursor to fetch the results since you are running dynamic SQL. There is a good example in the Teradata help doc on Dynamic SQL:
CREATE PROCEDURE GetEmployeeSalary
(IN EmpName VARCHAR(100), OUT Salary DEC(10,2))
BEGIN
DECLARE SqlStr VARCHAR(1000);
DECLARE C1 CURSOR FOR S1;
SET SqlStr = 'SELECT Salary FROM EmployeeTable WHERE EmpName = ?';
PREPARE S1 FROM SqlStr;
OPEN C1 USING EmpName;
FETCH C1 INTO Salary;
CLOSE C1;
END;
You can't use INTO in Dynamic SQL in Teradata.
As a workaround you need to do a cursor returning a single row:
DECLARE cnt BIGINT;
DECLARE cnt_cursor CURSOR FOR S;
SET v_sql_stmt = ' SELECT COUNT(*) FROM ' || P_TableName;
PREPARE S FROM v_sql_stmt;
OPEN cnt_cursor;
FETCH cnt_cursor INTO cnt;
CLOSE cnt_cursor;
I need to create select statement in post_insert trigger. Is it possible if yes then how?
I want to check another table records if it exists then it will update it otherwise insert as new record. Please help.
My block code is that i want to run
DECLARE
EXSIST_TYPE varchar2(50);
EXSIST_NAME varchar2(50);
EXSIST_COMPANY VARCHAR2(100);
BEGIN
SELECT PRO_TYPE, PRO_NAME, COMPANY_NAME INTO EXSIST_TYPE, EXSIST_NAME ,EXSIST_COMPANY FROM STOCK;
IF
:PURCHASE_DETAIL.PRO_TYPE <> EXSIST_TYPE AND
:PURCHASE_DETAIL.PRO_NAME <> EXSIST_NAME AND
:PURCHASE_DETAIL.COMPANY_NAME <> EXSIST_COMPANY THEN*/
IF
:PURCHASE.RADIO_TYPE = 'PURCHASE' THEN
INSERT INTO STOCK(
PRO_TYPE ,
PRO_NAME ,
COMPANY_NAME ,
QUANTITY ,
PURCHASE_RATE,
SALE_RATE ,
RACK_NUM
)
VALUES
(
:PURCHASE_DETAIL.PRO_TYPE,
:PURCHASE_DETAIL.PRO_NAME,
:PURCHASE_DETAIL.COMPANY_NAME,
:PURCHASE_DETAIL.QUANTITY,
:PURCHASE_DETAIL.PRICE,
:PURCHASE_DETAIL.SALE_PRICE,
:PURCHASE_DETAIL.RACK_NUM
);
END IF;
ELSIF
:PURCHASE_DETAIL.PRO_TYPE = EXSIST_TYPE AND
:PURCHASE_DETAIL.PRO_NAME = EXSIST_NAME AND
:PURCHASE_DETAIL.COMPANY_NAME = EXSIST_NAME THEN
IF
:PURCHASE.RADIO_TYPE = 'PURCHASE' THEN
UPDATE STOCK SET
STOCK.QUANTITY = STOCK.QUANTITY+:PURCHASE_DETAIL.QUANTITY
WHERE
STOCK.PRO_TYPE = :PURCHASE_DETAIL.PRO_TYPE AND
STOCK.PRO_NAME = :PURCHASE_DETAIL.PRO_NAME AND
STOCK.COMPANY_NAME= :PURCHASE_DETAIL.COMPANY_NAME;
ELSIF
:PURCHASE.RADIO_TYPE = 'PRCH_RETURN' THEN
UPDATE STOCK SET
STOCK.QUANTITY = STOCK.QUANTITY-:PURCHASE_DETAIL.QUANTITY
WHERE
STOCK.PRO_TYPE = :PURCHASE_DETAIL.PRO_TYPE AND
STOCK.PRO_NAME = :PURCHASE_DETAIL.PRO_NAME AND
STOCK.COMPANY_NAME = :PURCHASE_DETAIL.COMPANY_NAME;
END IF;
END IF;
END;
You never said what happened when you ran that code.
Anyway: requirement you mentioned ("if it exists then it will update it otherwise insert") looks like an excellent candidate for a MERGE statement (also called upsert, as a combination of UPdate and inSERT).
As Forms 6i is an old piece of software, I'm pretty much sure that MERGE can't directly be used there. However, if the underlying database is at least 9i, MERGE will work - create a stored procedure that contains MERGE, and pass form items' values as parameters.
Here's an example (taken from here; have a look for more examples. I'm lazy to create my own code):
MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
i have a table with 4 columns
1.msisdn
2.accountnumber
3.cardnumber
4.subscriptiondate
I want to add a trigger to this table. If the data i am inserting is
1.99999999
2.2
3.3298572857239
4.(this can be blank)
and the data that is currently in the table is
1.99999999
2.1
3.3298572857239
4.(this can be blank)
Trigger should check if there is this msisdn 99999999 is already having a record with this cardnumber 3298572857239. If there is a record already existing in the table, the trigger should delete the existing entry and insert the new one. The final result should look like this
1.99999999
2.1
3.3298572857239
4.(this can be blank)
I want to keep the value of accountnumber same before and after the trigger. This is what i have tried so far but for this trigger, i am not getting any data in accountnumber column. Please someone help
DROP TRIGGER TRIG_TABLEA;
CREATE OR REPLACE TRIGGER TRIG_TABLEA
BEFORE INSERT ON TABLEA
REFERENCING OLD AS Old NEW AS New
FOR EACH ROW
BEGIN
:new.accountnumber := :old.accountnumber;
DELETE FROM TABLEA WHERE MSISDN = :new.MSISDN AND CARDNUMBER = :new.CARDNUMBER;
:new.MSISDN := :new.MSISDN;
:new.CARDNUMBER := :new.CARDNUMBER;
:new.accountnumber := :old.accountnumber;
END;
/
Don't do a delete-and-insert. You want MERGE. The only thing that can change in your statement is accountnumber and subscriptiondate. You don't say where the data is coming from, so I assume this is a PL/SQL procedure with p_* as the parameters. So you want something like this:
MERGE INTO mytable trg
USING ( SELECT p_accountnumber, p_subscriptiondate FROM dual ) src
ON ( trg.msisdn = p_msisdn AND trg.cardnumber )
WHEN NOT MATCHED INSERT ( msisdn, accountnumber, cardnumber, subscriptiondate )
VALUES ( p_msisdn, p_accountnumber, p_cardnumber, p_subscriptiondate )
WHEN MATCHED SET ( cardnumber = p_cardnumber, subscriptiondate = p_subscriptiondate)
This will do an insert if the row doesn't exist or update an existing row if it does.
I have one table named Test with columns named ID,Name,UserValue,AverageValue
ID,Name,UserValue,AverageValue (As Appears on Table)
1,a,10,NULL
2,a,20,NULL
3,b,5,NULL
4,b,10,NULL
5,c,25,NULL
I know how to average the numbers via (SELECT Name, AVG(UserValue) FROM Test GROUP BY Name)
Giving me:
Name,Column1(AVG(Query)) (As Appears on GridView1 via databind when I run the website)
a,15
b,7.5
c,25
What I need to do is make the table appear as such by inserting the calculated AVG() into the AverageValue column server side:
ID,Name,UserValue,AverageValue (As Appears on Table)
1,a,10,15
2,a,20,15
3,b,5,7.5
4,b,10,7.5
5,c,25,25
Conditions:
The AVG(UserValue) must be inserted into Test table AverageValue.
If new entries are made the AverageValue would be updated to match AVG(UserValue).
So what I am looking for is a SQL command that is something like this:
INSERT INTO Test (AverageValue) VALUES (SELECT Name, AVG(UserValue) FROM Test GROUP BY Name)
I have spent considerable amount of time searching on google to find an example but have had no such luck. Any examples would be greatly appreciated. Many thanks in advance.
Try this:
with toupdate as (
select t.*, avg(uservalue) over (partition by name) as newavg
from test t
)
update toupdate
set AverageValue = newavg;
The CTE toupdate is an updatable CTE, so you can just use it in an update statement as if it were a table.
I believe this will do the trick for you. I use the merge statement a lot! It's perfect for doing things like this.
Peace,
Katherine
use [test_01];
go
if object_id (N'tempdb..##test', N'U') is not null
drop table ##test;
go
create table ##test (
[id] [int] identity(1, 1) not null,
[name] [nvarchar](max) not null,
[user_value] [int] not null,
[average_value] [decimal](5, 2),
constraint [pk_test_id] primary key([id])
);
go
insert into ##test
([name], [user_value])
values (N'a',10),
(N'a',20),
(N'b',5),
(N'b',10),
(N'c',25);
go
with [average_builder] as (select [name],
avg(cast([user_value] as [decimal](5, 2))) as [average_value]
from ##test
group by [name])
merge into ##test as target
using [average_builder] as source
on target.[name] = source.[name]
when matched then
update set target.[average_value] = source.[average_value];
go
select [id], [name], [user_value], [average_value] from ##test;
go
Hi
I have DAL Layer, from where invoking a stored procedure to insert values into the table.
E.g.:-
CREATE PROCEDURE [dbo].[DataInsert]
#DataName nvarchar(64)
AS
BEGIN
INSERT INTO
table01 (dataname)
VALUES
(#dataname)
END
Now as requirement changed, per client request i have to add values 5 times. So what is the best practice?
Do i call this Stored Procedure 5 times from my DAL?
or
Pass all the values (may be comma separated) to storedprocedure in one go and then let the stored procedure add it for 5 times?
BTW. Its not always 5 times. It is changeable.
You could create a user-defined table type;
CREATE TYPE [dbo].[SomeInfo] AS TABLE(
[Id] [int] NOT NULL,
[SomeValue] [int] NOT NULL )
Define your stored proc as such;
CREATE PROCEDURE [dbo].[AddSomeStuff]
#theStuff [SomeInfo] READONLY
AS
BEGIN
INSERT INTO SOMETABLE ([...columns...])
SELECT [...columns...] from #theStuff
END
Then you'll need to create a datatable (called table below) that matches the schema and call the stored proc as so;
var cmd = new SqlCommand("AddSomeStuff", sqlConn) {CommandType = CommandType.StoredProcedure};
var param = new SqlParameter("#theStuff", SqlDbType.Structured) {Value = table};
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
btw this proc works - I've just written and tested it see results below!
CREATE PROCEDURE [dbo].[DataInsert]
#DataName nvarchar(max) AS
BEGIN
DECLARE #pos SMALLINT, #str VARCHAR(max)
WHILE #DataName <> ''
BEGIN
SET #pos = CHARINDEX(',', #DataName)
IF #pos>0
BEGIN
SET #str = LEFT(#DataName, #pos-1)
SET #DataName = RIGHT(#DataName, LEN(#DataName)-#pos)
END
ELSE
BEGIN
SET #str = #DataName
SET #DataName = ''
END
INSERT INTO table01 VALUES(CONVERT(VARCHAR(100),#str))
END
END
GO
then run it: -
EXEC #return_value = [dbo].[DataInsert]
#DataName = N'five, bits, of, your, data'
*rows from table01: *
five
bits
of
your
data
(5 row(s) affected)
I'd either call your proc repeatedly(that would be my choice), or else you could use XML to pass in a list of values as a single parameter.
http://support.microsoft.com/kb/555266
Instead of fancy SQL code that is difficult to maintain and is not scalable, I would simply go to invoking your stored procedure multiple times.
If performance or transactional behavior is an issue, you can consider to send the commands in a single batch.
You talked about 5 insert. If the number of record to insert is much greater, you could consider bulk insert as well.