473,382 Members | 1,426 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,382 software developers and data experts.

Trigger and Row Update Help

I have a table that matches up Securities and Exchanges. Individual
securities can belong on multiple exchanges. One of the columns, named
PrimaryExchangeFlag, indicates if a particular exchange is the primary
exchange for that symbol. Each symbol can only have one primary
exchange.

I am trying to write a insert/update/delete trigger that enforces this
rule. The rules I have thought of are as follows:

Insert If new row has flag set, turn off flag for other rows for
that symbol. Otherwise, do nothing.

Update If updated row has flag set, turn off flag for other rows
for that symbol. Otherwise, set flag on first (MAX or MIN or TOP 1
???) row for that symbol.

Delete If deleted row had flag set, set flag on first row for that
symbol. Otherwise, do nothing.

My basic problem is how to do this when the trigger gets thrown for
multiple rows. (Since SQL does not throw individual triggers for each
row.)

Thanks.
Jul 20 '05 #1
8 8575
Sorry. I should have included some test code to make it easier for you.
Cutting and pasting will give you a test table and some
insert/delete/update statements.

USE tempdb
GO

DROP TABLE TestTable
GO

CREATE TABLE TestTable (
[Symbol] VARCHAR(15),
[Exchange] VARCHAR(5),
[PrimaryFlag] BIT
)
GO

INSERT INTO TestTable VALUES ('MSFT', 'XNAS', 1) -- first row - so flag
should be set
INSERT INTO TestTable VALUES ('QQQ', 'XNYS', 1) -- first row - so flag
should be set
INSERT INTO TestTable VALUES ('QQQ', 'XASE', 1) -- second row - so flag
should be set, but previous row should be unset
INSERT INTO TestTable VALUES ('MSFT', 'XASE', 0) -- second row - should
be unset for this, previous row not changed

UPDATE TestTable SET [PrimaryFlag] =1 WHERE [Symbol] = 'MSFT' AND
[Exchange] = 'XASE' -- set flag, unset first row

DELETE FROM TestTable WHERE [Symbol] = 'QQQ' AND [Exchange] = 'XASE' --
first row should be set
DELETE FROM TestTable WHERE [Symbol] = 'MSFT' AND [Exchange] = 'XASE' --
no change to flags
GO

SELECT * FROM [TestTable]

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!
Jul 20 '05 #2
>> I have a table that matches up Securities and Exchanges. <<

Then let's use a meaningful names, reasonable data types, keys and
constraints even in the sample data. Are there really CHAR(15)
symbols in use today? And they vary in length, too?

There is not such thing as an ordering in an SQL database, so all that
talk about "first row", "second row" etc. is totally meaningless.
This is not a file system; all relationships are shown as values in
columns. Never write with BIT datatypes and flags. The datatype is
proprietary, and the use of flags is bad SQL programming. Let's try
again with good DDL:

CREATE TABLE SecuritiesExchanges
(symbol CHAR(5) NOT NULL,
exchange_code CHAR(5) NOT NULL
CHECK (exchange_code IN ()),
exch_prefer INTEGER DEFAULT 1 NOT NULL -- order them!
CHECK (exch_prefer >= 0),
PRIMARY KEY (exchange, symbol, exch_prefer));

Let (exch_prefer = 1) mark the primary exchange and re-write your
rules in stored procedures that you will use to insert/update/delete
from the table.

Insertion: If I add a new (exchange, symbol) then I have to mark it as
the primary exchange for that security or not.

BEGIN
IF @make_primary = 'N'
THEN INSERT INTO SecuritiesExchanges
VALUES (@my_symbol, @my_exchange_code,
(SELECT MAX(S1.exch_prefer) + 1
FROM SecuritiesExchanges AS S1
WHERE S1.symbol = ScuritiesExchanges.symbol));
IF @make_primary = 'Y'
THEN BEGIN
UPDATE SecuritiesExchanges
SET exch_prefer = exch_prefer +1
WHERE S1.symbol = ScuritiesExchanges.symbol;
INSERT INTO SecuritiesExchanges
VALUES @my_symbol, @my_exchange_code, 1);
END;
ELSE PRINT 'Flag must be Y or N' END IF;
END;

Deletion: If I delete a (exchange, symbol) then I have to renumber all
of the exch_prefer values for that symbol.

BEGIN
DELETE FROM SecuritiesExchanges
WHERE symbol = @my_symbol
AND exchange_code = @my_exchange_code;
UPDATE SecuritiesExchanges
SET exch_prefer
= (SELECT COUNT (S1.exch_prefer)
FROM SecuritiesExchanges AS S1
WHERE S1.exch_prefer
<= SecuritiesExchanges.exch_prefer
AND S1.symbol
<= SecuritiesExchanges.symbol)
WHERE symbol = @my_symbol;
END;

Update: If I update an existing (exchange, symbol) then I have to mark
it as the primary exchange for that security or not. I also might
want to re-order the preferences, so I'll need better specs before
doing that code. But it is all simple algebra.
Jul 20 '05 #3
Joe,

First off. Thank you for responding.

Quess I will just rattle off my questions (or answer some of yours).

1) What is wrong with my names? They sound reasonable to me. No
abbreviations and the name tells you want the column represents.

2) Yes there are variable length (and greater than) 5 character
symbols. NYSE and Amex symbols are normally 3 or less characters while
Nasdaq are 4 or 5. But NYSE symbols can also have a prefix that
indicates if it is preferred, class a or b, warrant, or some
combination of them. So a 3 character preferred class a stock would be
ABC.PRA (making 7 characters. To take this further, some foreign
exchanges do not use symbols but use what is called an ISIN number
(which is 7 characters).

3) I realize that there is no such thing as first or second row. I was
merely using those words in comments to signify a particular row being
inserted before the others. In other words, the MSFT/XNAS row was
inserted first, then the MSFT/ASE row was inserted.

4) Did not know about the BIT datatype. Good to know.

5) When you say that flags are bad SQL programming, you are talking
about true/false or yes/no types of columns? Your comment says to
order them using integer values. In my case, each symbol only has ONE
primary exchange, the rest are not. There is no preference or order to
the none primary exchanges.

6) Why code the one-and-only-one primary exchange logic in a stored
procedure as opposed to a trigger? By having it in a stored procedure
I am limited to single security inserts since cannot pass datasets as
parameters. I can also have the problem of having somebody NOT use the
SP and then I have multiple primary exchanges for a single security.

Again. Thank you for the help. Hope my ignorance does not annoy you
too much.
Jul 20 '05 #4
Jason (Ja*******@hotmail.com) writes:
I have a table that matches up Securities and Exchanges. Individual
securities can belong on multiple exchanges. One of the columns, named
PrimaryExchangeFlag, indicates if a particular exchange is the primary
exchange for that symbol. Each symbol can only have one primary
exchange.

I am trying to write a insert/update/delete trigger that enforces this
rule. The rules I have thought of are as follows:

Insert If new row has flag set, turn off flag for other rows for
that symbol. Otherwise, do nothing.

Update If updated row has flag set, turn off flag for other rows
for that symbol. Otherwise, set flag on first (MAX or MIN or TOP 1
???) row for that symbol.

Delete If deleted row had flag set, set flag on first row for that
symbol. Otherwise, do nothing.

My basic problem is how to do this when the trigger gets thrown for
multiple rows. (Since SQL does not throw individual triggers for each
row.)


The repro below includes a trigger that seems to fulfil the requirements.
To be able to determine "first row", I added an exch_no column. I also
added PRIMARY KEY and UNIQUE constraints to set the frames for what I'm
working with.

There is one potential problem: if you update PrimaryFlag for the
row with the lowest exch_no to 0 and if it was 1 before, the trigger
will flip it back to 1. This situation was not covered in your requirements.

The UPDATE statement in the trigger includes an EXISTS clause within
comments. As far as I can see, this clause is not needed from a functional
point of view. For performance, it could have. Then again, accessing
the inserted/deleted tables can be expensive, why it is often a good
idea to read them into a temp table or table variable.

Finally, if you expect one-row operations to be common, it may be a good
idea to say IF @@rowcount = 1 first in the trigger and have a special
code path for this case, as you may avoid performance problems in this
case.

Here is a script:

CREATE TABLE TestTable (
[Symbol] VARCHAR(15),
[Exchange] VARCHAR(5),
exch_no int,
[PrimaryFlag] BIT,
CONSTRAINT pk_exch PRIMARY KEY (Symbol, Exchange),
CONSTRAINT u_exch UNIQUE (Symbol, exch_no)
)
go
CREATE TRIGGER testtable_tri on TestTable FOR
INSERT, UPDATE, DELETE AS

UPDATE TestTable
SET PrimaryFlag = 0
FROM TestTable t
WHERE EXISTS (SELECT *
FROM inserted i
WHERE t.Symbol = i.Symbol
AND t.Exchange <> i.Exchange
AND i.PrimaryFlag = 1)

UPDATE TestTable
SET PrimaryFlag = 1
FROM TestTable t
JOIN (SELECT t.Symbol, exch_no = MIN(t.exch_no)
FROM TestTable t
WHERE t.PrimaryFlag = 0
AND NOT EXISTS (SELECT *
FROM TestTable t2
WHERE t2.Symbol = t.Symbol
AND t2.PrimaryFlag = 1)
GROUP BY t.Symbol) AS t3
ON t.Symbol = t3.Symbol
AND t.exch_no = t3.exch_no
/*WHERE EXISTS (SELECT *
FROM deleted d
WHERE d.Symbol = t.Symbol)*/
GO

INSERT INTO TestTable VALUES ('MSFT', 'XNAS', 1, 1)
-- first row - so flagshould be set
INSERT INTO TestTable VALUES ('QQQ', 'XNYS', 1, 1)
-- first row - so flag should be set
INSERT INTO TestTable VALUES ('QQQ', 'XASE', 2, 1)
-- second row - so flag should be set, but previous row should be unset
INSERT INTO TestTable VALUES ('MSFT', 'XASE', 2, 0)
-- second row - should be unset for this, previous row not changed

select * from TestTable ORDER BY Symbol, exch_no

UPDATE TestTable SET [PrimaryFlag] =0
WHERE [Symbol] = 'QQQ' AND [Exchange] = 'XNYS'
-- set flag, unset first row

select * from TestTable ORDER BY Symbol, exch_no

DELETE FROM TestTable WHERE [Symbol] = 'QQQ' AND [Exchange] = 'XASE'
-- first row should be set
DELETE FROM TestTable WHERE [Symbol] = 'MSFT' AND [Exchange] = 'XASE'
-- no change to flags
GO

SELECT * FROM [TestTable] ORDER BY Symbol, exch_no

--
Erland Sommarskog, SQL Server MVP, so****@algonet.se

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techinf...2000/books.asp
Jul 20 '05 #5
Jason (Ja*******@hotmail.com) writes:
1) What is wrong with my names? They sound reasonable to me. No
abbreviations and the name tells you want the column represents.
There is nothing wrong with your names. Of course, "exchange" is a little
abstract for someone who don't know the business domain, but that is
not relevant.
3) I realize that there is no such thing as first or second row. I was
merely using those words in comments to signify a particular row being
inserted before the others. In other words, the MSFT/XNAS row was
inserted first, then the MSFT/ASE row was inserted.
Joe has a point so far that you need to somehow cover this in the data
model. Of course, "first" could also mean the alphabetic order of the
exchange code, or whatever.
4) Did not know about the BIT datatype. Good to know.
Unless you are striving for portability, there is no reason to stay away
from datatypes that are proprietary to SQL Server. Joe Celko seems to
think that everyone changes their DB engine at least twice a year.
5) When you say that flags are bad SQL programming, you are talking
about true/false or yes/no types of columns? Your comment says to
order them using integer values. In my case, each symbol only has ONE
primary exchange, the rest are not. There is no preference or order to
the none primary exchanges.
Good knows what Joe meant. Joe is good if you want to know some theory,
or help devlish SELECT statements. But for general programming help
for MS SQL Server his advice are not always appropriate.
6) Why code the one-and-only-one primary exchange logic in a stored
procedure as opposed to a trigger? By having it in a stored procedure
I am limited to single security inserts since cannot pass datasets as
parameters. I can also have the problem of having somebody NOT use the
SP and then I have multiple primary exchanges for a single security.


Actually, you can pass data sets to stored procedures these days, thanks
to the wonders of XML.

That said, your comment is very relevant. Whether to use a trigger or to
have the logic in a stored procedure is a question that is always open
for discussion. Having a trigger, means that if someone bypasses the
trigger by running an SQL statement direct, you maintain the logic.
However, a trigger can be dropped or disabled, and if this happens,
your updating logic will fail silently. A stored procedure can also
be dropped, but attempts to call it will give an error message.
--
Erland Sommarskog, SQL Server MVP, so****@algonet.se

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techinf...2000/books.asp
Jul 20 '05 #6
Thanks for the help.

Going back and rereading my own post exposed some questionable
requirements.

If the security that is being updated currently has the primary
exchange flag set and you are currently trying to turn it off, who
then becomes the primary exchange?!

One possible answer would be SELECT TOP 1 but a better response would
be not to allow it to happen. The business rule should probably be
that a security cannot have its primary flag unset manually, but can
only be changed by setting another row as the primary.
Jul 20 '05 #7
>> 1) What is wrong with my names? They sound reasonable to me. No
abbreviations and the name tells you want the column represents. <<

ISO-11179 is more of a "genus-specie" model. If these are known in
your trade, then they can stand along
2) Yes there are variable length (and greater than) 5 character symbols) <<

That is one I did not know! I am still tryignto figure out CUSIP
rules. Thanks!
5) When you say that flags are bad SQL programming, you are talking about true/false or yes/no types of columns? <<

They are all too often a computed column. You would not store the
total cost of a line item in an invoice detail when you have price and
quantity in the same row. You would not store the total cost of an
invoice in an invoice header when you can computer them from the
invoice details. It is faster these days to compute them as needed
and it is safer (we used to have to do this with punch cards for
physical reasons). So why would you have the logical status in a
computed column either?
In my case, each symbol only has ONE primary exchange, the rest are not. There is no preference or order to the none primary exchanges. <<

Then consider just "prefer = 1 or prefer >1 " in your queries. The
sequence gives you a simple datatype with easy validation and update
rules. Bits don't.
6) Why code the one-and-only-one primary exchange logic in a stored procedure as opposed to a trigger? <<

Triggers are less portable in SQL Server. I also assume that you
would do other edits in the SP.
I can also have the problem of having somebody NOT use the SP and

then I have multiple primary exchanges for a single security. <<

Good point. If we get to full Standard SQL-92, you can do it with a
CHECK() constraint, which would be the best way.
Jul 20 '05 #8
>> I can also have the problem of having somebody NOT use the SP and
then I have multiple primary exchanges for a single security. <<

CREATE TABLE SecuritiesExchanges
(symbol CHAR(5) NOT NULL,
exchange_code CHAR(5) NOT NULL
CHECK (exchange_code IN ()),
exch_prefer INTEGER DEFAULT 1 NOT NULL
CHECK (exch_prefer >= 0),
PRIMARY KEY (exchange, symbol, exch_prefer),
UNIQUE (symbol, exch_prefer) -- does that do it?
);
Jul 20 '05 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: m3ckon | last post by:
Hi there, I'm a little stuck and would like some help I need to create an update trigger which will run an update query on another table. However, What I need to do is update the other...
9
by: Martin | last post by:
Hello, I'm new with triggers and I can not find any good example on how to do the following: I have two tables WO and PM with the following fields: WO.WONUM, VARCHAR(10) WO.PMNUM,...
3
by: takilroy | last post by:
Hi, Does anyone know of a simple way to do this? I want to create an insert trigger for a table and if the record already exists based on some criteria, I want to update the table with the...
33
by: coosa | last post by:
I have a table: ---------------------------------------------------- CREATE TABLE CATEGORY ( CATEGORY_ID INTEGER IDENTITY(1,1) NOT NULL, CATEGORY_NAME VARCHAR(40) NOT NULL,...
5
by: Peter Erickson | last post by:
I am running postgresql 7.4.2 and having problems creating a trigger function properly. I keep getting the following error: ERROR: OLD used in query that is not in rule I have a table called...
4
by: SUKRU | last post by:
Hello everybody. Unfortunately I am pretty new to sql-server 2000 I need some help with a Trigger I created. I created a trigger witch takes the id of the affected row and does a update on a...
3
by: teddysnips | last post by:
I need a trigger (well, I don't *need* one, but it would be optimal!) but I can't get it to work because it references ntext fields. Is there any alternative? I could write it in laborious code...
2
by: mob1012 via DBMonster.com | last post by:
Hi All, I wrote last week about a trigger problem I was having. I want a trigger to produce a unique id to be used as a primary key for my table. I used the advice I received, but the trigger is...
3
by: Sam Durai | last post by:
Need help to write a trigger according to the following business requirement. This on DB2 UDB V8.2 / AIX 5.3 Whenever a 100th record is inserted into my 'ACCOUNT' table with a particular...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.