show the warning message and save the transaction - triggers

i want a create trigger like that. when balance over 500 thats save the transaction but not show any message. How i fix this.
create Trigger [dbo].[balance] On [dbo].[orders]
After Insert as
Declare
#or_kod VARCHAR(25),
#balance float(10),
#message varchar(max)
Begin
/*
Message
*/
select #message= 'Balance over 500 !!!'
/*
or_kod
*/
Select #or_kod = or_customer_kod From inserted
/*
Balance
*/
Select #balance = dbo.fn_accountBalance('',0,or_customer_kod,'','',NULL,NULL,NULL,0,0,0,0,0) From inserted
/*
IF Balance over 500
*/
IF ( #balance>500)
begin
commit TRANSACTION
raiserror(#message,10,1)
end
end

Related

TSQL: How to avoid cursors

I've created a trigger on the table Customer that adds the email address 'PW#essef.be' to the table eMail when 'PW' is selected as representative (CustomerRep) in the table Customer.
The trigger works but, to make multi-row updates possible, I used a cursor. Now, I keep reading that cursors are a bad idea, so I'd like to convert the trigger below. How can I do this, please?
ALTER TRIGGER tUpdate_Customer ON Customer FOR INSERT, UPDATE AS
BEGIN
SET NOCOUNT ON
DECLARE #CustomerID AS INT
DECLARE cCustomer SCROLL CURSOR FOR SELECT CustomerID FROM INSERTED WHERE CustomerRep='PW'
OPEN cCustomer
FETCH FIRST FROM cCustomer INTO #CustomerID
WHILE ##FETCH_STATUS = 0
BEGIN
IF ISNULL((SELECT 'X' AS Found FROM eMail WHERE eMailCustomerID=#CustomerID AND eMail='PW#essef.be'), '-')<>'X'
INSERT INTO eMail (eMailCustomerID, eMail) VALUES (#CustomerID, 'PW#essef.be')
FETCH NEXT FROM cCustomer INTO #CustomerID
END
CLOSE cCustomer
DEALLOCATE cCustomer
END
Had a blind go there, but try this:
ALTER TRIGGER tUpdate_Customer ON Customer FOR INSERT, UPDATE AS
BEGIN
SET NOCOUNT ON
INSERT INTO eMail (eMailCustomerID, eMail)
SELECT i.CustomerID,'PW#essef.be'
FROM inserted as i
WHERE
i.CustomerRep='PW'
AND EXISTS
(
SELECT 1
FROM eMail as e
WHERE e.eMailCustomerID=i.CustomerID AND e.eMail='PW#essef.be'
)
END

How to optimize postgresql procedure

I have 61 million of non unique emails with statuses.
This emails need to deduplicate with logic by status.
I write stored procedure, but this procedure runs to long.
How I can optimize execution time of this procedure?
CREATE OR REPLACE FUNCTION public.load_oxy_emails() RETURNS boolean AS $$
DECLARE
row record;
rec record;
new_id int;
BEGIN
FOR row IN SELECT * FROM oxy_email ORDER BY id LOOP
SELECT * INTO rec FROM oxy_emails_clean WHERE email = row.email;
IF rec IS NOT NULL THEN
IF row.status = 3 THEN
UPDATE oxy_emails_clean SET status = 3 WHERE id = rec.id;
END IF;
ELSE
INSERT INTO oxy_emails_clean(id, email, status) VALUES(nextval('oxy_emails_clean_id_seq'), row.email, row.status);
SELECT currval('oxy_emails_clean_id_seq') INTO new_id;
INSERT INTO oxy_emails_clean_websites_relation(oxy_emails_clean_id, website_id) VALUES(new_id, row.website_id);
END IF;
END LOOP;
RETURN true;
END;
$$
LANGUAGE 'plpgsql';
How I can optimize execution time of this procedure?
Don't do it with a loop.
Doing a row-by-row processing (also known as "slow-by-slow") is almost always a lot slower then doing bulk changes where a single statement processes a lot of rows "in one go".
The change of the status can easily be done using a single statement:
update oxy_emails_clean oec
SET status = 3
from oxy_email oe
where oe.id = oec.id
and oe.status = 3;
The copying of the rows can be done using a chain of CTEs:
with to_copy as (
select *
from oxy_email
where status <> 3 --<< all those that have a different status
), clean_inserted as (
INSERT INTO oxy_emails_clean (id, email, status)
select nextval('oxy_emails_clean_id_seq'), email, status
from to_copy
returning id;
)
insert oxy_emails_clean_websites_relation (oxy_emails_clean_id, website_id)
select ci.id, tc.website_id
from clean_inserted ci
join to_copy tc on tc.id = ci.id;

Stored Procedure to Email multiple recipients from query

I've created a query that pulls info and emails in the way that I need it to be presented to our clients. How can I turn this into a stored procedure fed by a query (query A)? I need it to run for each unique set of cmp_code and cmp_e_mail it returns. So for example if QueryA returns the following, I need the email query to run for each of them individually.
C0001 email1#asdf.com
C0002 email2#asdf.com
C0003 email3#asdf.com
QueryA:
SELECT DISTINCT
[cmp_code]
,[cmp_e_mail]
FROM Table1
Query to email:
DECLARE #email nvarchar(50)
DECLARE #cmp_code nvarchar (5)
DECLARE #profile nvarchar(50)
DECLARE #subject nvarchar(100)
DECLARE #querystr nvarchar (MAX)
set #email = QueryA.[cmp_e_mail]
set #cmp_code = QueryA.[cmp_code]
set #profile = 'Reports'
set #subject = 'Test'+#cmp_code
set #querystr = 'SELECT [Year],[Week],[DueDate]
FROM Table1
WHERE [cmp_code] = '''+#cmp_code+'''';
EXEC msdb.dbo.sp_send_dbmail
#profile_name = #profile,
#recipients = #email,
#subject = #subject,
#body = 'This message is to inform you that we have not received your financial report for the following weeks.
Please remit as soon as possible and pay by the due date listed.',
#query = #querystr
try create a stored procedure like this one below that loops through the table and then calls another stored procedure passing in the data , be sure to deallocate and close the cursor at the end
Declare #Code nvarchar(50)
Declare #EmailAddress nvarchar(Max)
Declare dbCurSP Cursor
For SELECT DISTINCT [cmp_code] FROM Table1
Open dbCurSP
Fetch Next From dbCurSP Into #Code
While ##fetch_status = 0
Begin
-- find email address
SELECT #EmailAddress= [cmp_e_mail] FROM Table1 where [cmp_code]=#Code
execute SP_SendEmail #EmailAddress, #Code
Fetch Next From dbCurSP Into #Code
End
Close dbCurSP
Deallocate dbCurSP

Sql Server Any data from the row itself with Try Catch?

Using Try/Catch with SqlServer 2008R2, is there a trick to getting some information out of the row that caused the error? For example,
BEGIN TRY
INSERT INTO MyTable
SELECT *
FROM #MyTableVar
END TRY
BEGIN CATCH
-- In here, is there some way to know, for example, MyTable.SomeColumn for the offending row?
END CATCH
This is what I ended up doing:
DECLARE #MyResults TABLE (
Id INT IDENTITY( 1, 1 )
TheKey VARCHAR(20),
Success BIT
)
-- Initially set Success to 1 for all rows
INSERT INTO #MyResults
SELECT TheKey, 1
FROM #MyTableVar
DECLARE #CurrentKey VARCHAR(20)
DECLARE #CurrentId INT
DECLARE incoming CURSOR FOR SELECT Id, TheKey FROM #MyResults
OPEN incoming
FETCH incoming into #Id, #CurrentKey
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN TRY
INSERT INTO OfficialTable
SELECT *
FROM #MyTableVar TV
WHERE TV.TheKey = #CurrentKey
END TRY
BEGIN CATCH
-- On any failure, update the proper row in #MyResults
UPDATE #MyResults
SET Success = 0
WHERE TheKey = #CurrentKey AND Id = #CurrentId
END CATCH
FETCH NEXT FROM incoming INTO #Id, #CurrentKey
END
CLOSE incoming
SELECT * FROM #MyResults
In the CATCH, I know the key to #MyTableVar, so, I should be able to look up anything I need with that.

TSQL break loop when ##ROWCOUNT = 0

I have insert statements (simplified) in a SPROC like the following
SET ROWCOUNT 100
WHILE(1=1)
BEGIN
INSERT INTO table1
SELECT *
FROM table2
WHERE some_condition
-- EDIT: Realized forgot to include this following vital line that is causing issue
SET #var = #var + ##ROWCOUNT
-- ##ROWCOUNT now takes on a value of 1, which will cause the following IF check to fail even when no lines are inserted
IF(##ROWCOUNT = 0)
BEGIN
BREAK
END
END
But the issue is, after any operation even when no more rows fit my some_condition, ##ROWCOUNT is equal to 1, not 0.
How can I break that loop when there are 0 rows returned matching my some_condition?
The "set" statement creates a row count of 1. What you should do is immediately save ##ROWCOUNT into a #rowCount variable and use that var later on.
declare #rowCount int
WHILE(1=1)
BEGIN
INSERT INTO table1
SELECT *
FROM table2
WHERE some_condition
-- EDIT: Realized forgot to include this following vital line that is causing issue
SET #rowCount = ##ROWCOUNT
SET #var = #var + #rowCount
-- ##ROWCOUNT now takes on a value of 1, which will cause the following IF check to fail even when no lines are inserted
IF(#rowCount = 0)
BEGIN
BREAK
END
END
Also, you can simplify by setting #rowCount to -1 initially and changing the WHILE condition to #rowCount <> 0. The conditional BREAK will no longer be needed.
An alternative solution. This checks each iteration to see if the ID of the last inserted record has changed or not. If it hasn't changed, it indicates that no records were added that iteration.
SET ROWCOUNT 100
declare #id int;
WHILE(1=1)
INSERT INTO table1
SELECT *
FROM table2
WHERE some_condition
IF(#id= ##identity)
BEGIN
BREAK
END
set #id = ##identity;
END
Try this solutions:
1st solution
Using ##ROWCOUNT in loop's condition.
SET ROWCOUNT 100
INSERT INTO table1
SELECT *
FROM table2
WHERE some_condition
WHILE(##ROWCOUNT > 0)
BEGIN
INSERT INTO table1
SELECT *
FROM table2
WHERE some_condition
END
2nd solition
Using goto.
SET ROWCOUNT 100
WHILE(1=1)
BEGIN
INSERT INTO table1
SELECT *
FROM table2
WHERE some_condition
IF(##ROWCOUNT = 0)
BEGIN
goto label
END
END
label1:
print 'After lopp'
I think you should use select to get the ##rowcount into a variable. try this:
declare #number_of_rows int
SET ROWCOUNT 100
WHILE(1=1)
BEGIN
INSERT INTO table1
SELECT *
FROM table2
WHERE some_condition
SELECT #number_of_rows=##ROWCOUNT
IF (#number_of_rows = 0)
BEGIN
BREAK
END
END
Implemented solution similar to Moho, but used SELECT instead of SET to store ##ROWCOUNT.