How to auto calculate 2 column and display at one column? - sql

I want to alter, the table already created.
Column A + Column B = Column C.
Column A and B already has value, only C don't.
I just need to add function?
If so what is the function?
So next time I just need to add in the column A and B only, cause C already auto calculate

If your table currently has columns A and B but does not yet have C, then you can add it as a virtual column:
alter table your_table
add c number generated always as (a + b) virtual;
db<>fiddle
If A and/or B are nullable then you need to handle that; e.g. if you want to treat null as zero for the calculation you can do:
alter table your_table
add c number generated always as (coalesce(a, 0) + coalesce(b, 0)) virtual;
db<>fiddle
If the column already exists (as suggested by other comments) then you could use a trigger to maintain it for future updates/inserts, which could be as simple as:
create trigger trg_maintain_c
before insert or update on your_table
for each row
begin
:new.c := coalesce(:new.a, 0) + coalesce(:new.b, 0);
end;
/
and update existing values as a one-off exercise if needed.
db<>fiddle
But it would probably be simpler to drop it and re-add it as a virtual column, as it's less work to maintain and prevents the calculated column being directly updated to the wrong value. (Make sure you know what you're doing, and have any required permission/sign-off, before dropping an existing column, though...)

I think 2 ways to do that in order of what you have:
1 - You use a trigger when you add some data to A and B to automatically calculate C
2 - You create a query that calculate C given A and B
select c = a+b
from table
or something like that

Related

Moving data from one column to another in PostgreSQL

Sometimes, one might want to move some data from one column to another. By moving (in constrast to copying), I mean that the new column was originally null before doing the operation, and the old column should be set to null after doing the operation.
I have a table defined as such:
CREATE TABLE photos(id BIGSERIAL PRIMARY KEY, photo1 BYTEA, photo2 BYTEA);
Suppose there is an entry in the table where photo1 contains some data, and photo2 is NULL. I would like to make an UPDATE query wuch that photo1 becomes NULL and photo2 contains the data that was originally in photo1.
I issue the following SQL command (WHERE clause left out for brevity):
UPDATE photos SET photo2 = photo1, photo1 = NULL;
It seems to work.
I also tried it this way:
UPDATE photos SET photo1 = NULL, photo2 = photo1;
It also seems to work.
But is it guaranteed to work? Specifically, could photo1 be set to NULL before photo2 is set to photo1, thereby causing me to end up with NULL in both columns?
As an aside, this standard UPDATE syntax seems inefficient when my BYTEAs are large, as photo2 has to be copied byte-by-byte from photo1, when a simple swapping of pointers might have sufficed. Maybe there is a more efficient way that I don't know about?
This is definitely safe.
Column-references in the UPDATE refer to the old columns, not the new values. There is in fact no way to reference a computed new value from another column.
See, e.g.
CREATE TABLE x (a integer, b integer);
INSERT INTO x (a,b) VALUES (1,1), (2,2);
UPDATE x SET a = a + 1, b = a + b;
results in
test=> SELECT * FROM x;
a | b
---+---
2 | 2
3 | 4
... and the ordering of assignments is not significant. If you try to multiply-assign a value, you'll get
test=> UPDATE x SET a = a + 1, a = a + 1;
ERROR: multiple assignments to same column "a"
because it makes no sense to assign to the same column multiple times, given that both expressions reference the old tuple values, and order is not significant.
However, to avoid a full table rewrite in this case, I would just ALTER TABLE ... ALTER COLUMN ... RENAME ... then CREATE the new column with the old name.

Informix trigger for deleting one record

When I perform an task, two rows gets inserted in my table ie. duplication. I need to remove the duplicate by using an after insert trigger. I need to delete one duplicate record from those 2. I need something like this
CREATE TRIGGER del_rec
INSERT ON table1
AFTER(EXECUTE PROCEDURE del_proc());
CREATE PROCEDURE del_proc()
//check field a,b,c of this table already exists for this id. if yes delete the second one
END PROCEDURE;
For example:
table 1:
a b c d e
1 1 1 2 2
1 1 1 2 2
it should delete the second row.
Your table is misdesigned if duplicates can be inserted into it. You should have a unique constraint ensuring that it does not happen.
Assuming that you can't fix the table for some reason, then:
CREATE TRIGGER ins_table1
INSERT ON table1 REFERENCING NEW AS new
FOR EACH ROW (EXECUTE PROCEDURE ins_table1(new.a, new.b, new.c));
This assumes that columns a, b and c are sufficient to uniquely identify the row. I've renamed the trigger and procedure to more accurately reflect what/when they are relevant; del is not all that appropriate as a prefix for something called on INSERT.
CREATE PROCEDURE ins_table1(new_a INTEGER, new_b INTEGER, new_c INTEGER)
DEFINE l_a LIKE table1.a;
FOREACH SELECT a INTO l_a
FROM table1
WHERE a = new_a AND b = new_b AND c = new_c
RAISE EXCEPTION -271, -100;
END FOREACH;
END PROCEDURE;
This is called for each row that's inserted. If the SELECT statement returns a row, it will enter the body of the FOREACH loop, so the exception will be raised and the INSERT will be aborted with a more or less appropriate error (-271 Could not insert new row into the table; -100 ISAM error: duplicate value for a record with unique key).
If you try to do this validation with an AFTER trigger, you have to scan the entire table to see whether there are any duplicates, rather than just targeting the single key combination that was inserted. Note that in general, an INSERT can have multiple rows (think INSERT INTO Table SELECT * FROM SomeWhereElse). The performance difference will be dramatic! (Your query for an AFTER trigger would have to be something like SELECT a, b, c FROM table1 GROUP BY a, b, c HAVING COUNT(*) > 1.)
Why not just use SELECT UNIQUE to avoid inserting duplicate values, or to remove duplicate values which already exist in the table?

Question about multiplying columns in SQL

I was wondering if it was possible to multiply two columns and if so how would this take place
Suppose I have a table
a b
1 4
2 5
3 6
Could I do something like
SELECT a *b from table
Would this multiply the contents row by row then store it in a new column
Are these result right
4
10
18
That query would multiply the values, but it wouldn't "store it in a new column" To store it you would have to issue an update statement.
Assuming you add a new column ("c") to your table you could do:
update table
set c = a * b
If all you need is the new column in a result set, without modifying the underlying table you could:
select a, b, (a*b) as c from table
Yes you can perfectly do that.
update
To clarify: The query and output you mentioned in your question are correct.
Rather than storing a calculated column in a base table, consider a viewed table:
CREATE VIEW MyView
AS
SELECT a, b,
a * b AS my_calc
FROM MyTable;

Custom sort in SQL Server

I have a table where the results are sorted using an "ORDER" column, eg:
Doc_Id Doc_Value Doc_Order
1 aaa 1
12 xxx 5
2 bbb 12
3 ccc 24
My issue is to initially set up this order column as efficiently and reusably as possible.
My initial take was to set up a scalar function that could be used as a default value when a new entry is added to the table:
ALTER FUNCTION [dbo].[Documents_Initial_Order]
( )
RETURNS int
AS
BEGIN
RETURN (SELECT ISNULL(MAX(DOC_ORDER),0) + 1 FROM dbo.Documents)
When a user wants to permute 2 documents, I can then easily switch the 2 orders.
It works nicely, but I now have a second table I need to set up the same way, and I am quite sure there is a nicer way to do it. Any idea?
Based on your comment, I think you have a very workable solution. You could make it a little more userfriendly by specifying it as a default:
alter table documents
add constraint constraint_name
default (dbo.documents_initial_order()) for doc_order
As an alternative, you could create an update trigger that copies the identity field to the doc_order field after an insert:
create trigger Doc_Trigger
on Documents
for insert
as
update d
set d.doc_order = d.doc_id
from Documents d
inner join inserted i on i.doc_id = d.doc_id
Example defining doc_id as an identity column:
create table Documents (
doc_id int identity primary key,
doc_order int,
doc_value ntext
)
It sounds like you want an identity column that you can then override once it gets it initial value. One solution would be to have two columns, once call "InitialOrder", that is an auto-increment identity column, and then a second column called doc_order that initially is set to the same value as the InitialOrder field (perhaps even as part of the insert trigger or a stored procedure if you are doing inserts that way), but give the user the ability to edit that column.
It does require an extra few bytes per record, but solves your problem, and if its of any value at all, you would have both the inital document order and the user-reset order available.
Also, I am not sure if your doc_order needs to be unique or not, but if not, you can then sort return values by doc_order and InitialOrder to ensure a consistent return sequence.
If there is no need to have any control over what that DOC_ORDER value might be, try using an identity column.

How to set a default value for one column in SQL based on another column

I'm working with an old SQL 2000 database and I don't have a whole lot of SQL experience under my belt. When a new row is added to one of my tables I need to assign a default time value based off of a column for work category.
For example, work category A would assign a time value of 1 hour, category B would be 2 hours, etc...
It should only set the value if the user does not manually enter the time it took them to do the work. I thought about doing this with a default constraint but I don't think that will work if the default value has a dependency.
What would be the best way to do this?
I would use a trigger on Insert.
Just check to see if a value has been assigned, and if not, go grab the correct one and use it.
Use a trigger as suggested by Stephen Wrighton:
CREATE TRIGGER [myTable_TriggerName] ON dbo.myTable FOR INSERT
AS
SET NOCOUNT ON
UPDATE myTable
SET
timeValue = '2 hours' -- assuming string values
where ID in (
select ID
from INSERTED
where
timeValue = ''
AND workCategory = 'A'
)
Be sure to write the trigger so it will handle multi-row inserts. Do not process one row at a time in a trigger or assume only one row will be in the inserted table.
If what you are looking for is to define a column definition based on another column you can do something like this:
create table testable
(
c1 int,
c2 datetime default getdate(),
c3 as year(c2)
);
insert into testable (c1) select 1
select * from testable;
Your result set should look like this :
c1 | c2 | c3
1 | 2013-04-03 17:18:43.897 | 2013
As you can see AS (in the column definition) does the trick ;) Hope it helped.
Yeah, trigger.
Naturally, instead of hard-coding the defaults, you'll look them up from a table.
Expanding on this, your new table then becomes the work_category table (id, name, default_hours), and you original table maintains a foreign key to it, transforming fom
(id, work_category, hours) to (id, work_category_id, hours).
So, for example, in a TAG table (where tags are applied to posts) if you want to count one tag as another...but default to counting new tags as themselves, you would have a trigger like this:
CREATE TRIGGER [dbo].[TR_Tag_Insert]
ON [dbo].[Tag]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE dbo.Tag
SET [CountAs] = I.[ID]
FROM INSERTED AS I
WHERE I.[CountAs] IS NULL
AND dbo.Tag.ID = I.ID
END
I can think of two ways:
triggers
default value or binding (this should work with a dependency)
Triggers seem well explained here, so I won't elaborate. But generally I try and stay away from triggers for this sort of stuff, as they are more appropriate for other tasks
"default value or binding" can be achieved by creating a function e.g.
CREATE FUNCTION [dbo].[ComponentContractor_SortOrder] ()
RETURNS float
AS
BEGIN
RETURN (SELECT MAX(SortOrder) + 5 FROM [dbo].[tblTender_ComponentContractor])
END
And then setting the "default value or binding" for that column to ([dbo].ComponentContractor_SortOrder)
Generally I steer away from triggers. Almost all dbms have some sort of support for constraints.
I find them easier to understand , debug and maintain.