Trigger to prevent update in postgresql - sql

I want to create a trigger which will prevent update in a row from that table if that entry is present in another table too.
example
Table M
m_id title
1 abc
2 def
3 ghi
Table N
n_id m_id
1 2
2 3
so if try to update values 2 or 3 in table m it shouldn't allow that
whereas if i try to update value 1 from table it should do so.

You'll have to create a trigger BEFORE UPDATE ON m FOR EACH ROW that checks IF OLD.m_id <> NEW.m_id AND EXISTS (SELECT 1 FROM n WHERE n.m_id = OLD.m_id) and throws an exception in that case.

Related

Add new column to a table with a value group by value

I have a Circus table as follow
circus_id
circus_date
circus_show_price
1
09-12-2020
78
2
12-01-2021
82
and a Ticket table as follow
ticket_id
circus_id
ticket_category
1
1
Adult
2
1
Student
3
1
Children
4
2
Adult
5
2
Children
6
2
Adult
and i want to alter the circus table by adding a new column called ticket_sold and the value should be as follow
circus_id
circus_date
circus_show_price
ticket_sold
1
09-12-2020
78
3
2
12-01-2021
82
3
this is what I have tried
alter table circus add ticket_sold numeric(3) default 0;
update circus set ticket_sold = (select count(ticket_id) from ticket group by circus_id);
it gives me an error said
single-row subquery returns more than one row
In-general, don't, as you will end up with a ticket_sold column that rapidly becomes out-of-sync with the ticket table.
If you want to have a dynamically updating column then:
1. Use a view.
You can just compute the value whenever you need it:
CREATE VIEW circus_view (circus_id, circus_date, circus_show_price, tickets_sold) AS
SELECT c.circus_id,
c.circus_date,
c.circus_show_price,
(SELECT COUNT(*) FROM ticket t WHERE t.circus_id = c.circus_id)
FROM circus c;
2. Use a trigger.
If you must persist the number of tickets in the circus table then:
ALTER TABLE Circus ADD tickets_sold NUMBER;
CREATE TRIGGER circus_tickets
AFTER INSERT OR UPDATE OR DELETE ON Ticket
BEGIN
UPDATE Circus c
SET tickets_sold = (SELECT COUNT(*) FROM ticket t WHERE t.circus_id = c.circus_id);
END;
/
fiddle
Is is not group by clause you need because query then returns number of tickets per each circus, but - then you get as many rows as there are circus_ids in the ticket table. Instead, correlate subquery to the main table:
update circus c set
c.ticket_sold = (select count(t.ticket_id)
from ticket t
where t.circus_id = c.circus_id
);

Assign explicit version to existing rows of the table

I have a table where records are inserted and updated. In case of updates, a new row is inserted into the table. In order to track updates for a given record, there's a column added to the table called root_record_id which holds the id of the very first record in the update chain.
For eg: Consider the record table schema as follows:
id
root_record_id
other columns
1
1
...
2
2
...
3
1
...
4
1
...
5
2
...
In this case, a record with id=1 was inserted, which was then updated to id=3 and then to id=4. Similarly the record with id=2 was inserted and then updated to id=5.
I want to add a version column to this table, where version is incremented on each update and starts with 0.
id
root_record_id
version
other columns
1
1
0
...
2
2
0
...
3
1
1
...
4
1
2
...
5
2
1
...
I tried writing queries using group by clause on root_record_id but failed to accomplish the task.
If you are looking for the general sequence on how to add the column and then pre-fill the values, then follow this fiddle: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=5a04b49fbda3883a9605f5482e252a1b
Add the version column allowing nulls:
ALTER TABLE Records ADD version int null;
Update the version according to your logic:
UPDATE Records
SET version = lkp.version
FROM Records r
INNER JOIN (
SELECT Id, COUNT(root_record_id) OVER (partition by root_record_id ORDER BY id ASC)-1 as version
FROM Records
) lkp ON r.Id = lkp.Id;
Alter the version column to NOT allow nulls
ALTER TABLE Records ALTER COLUMN version int not null;
Finally, ensure that you increment the version column during new row inserts.
DBFIDDLE
This query produces the version that you can use (in an update, or in a trigger):
SELECT
id,
root_record_id,
RANK() OVER (partition by root_record_id ORDER BY id ASC)-1 version
FROM table1
ORDER BY id;
output:
id
root_record_id
version
1
1
0
2
2
0
3
1
1
4
1
2
5
2
1

How to find if all the columns in table A are present in table B or not

Table A
Id name phone
1 sam 7753457893
2 tom 7753457893
3 pop 7753457893
4 john 7753457893
table B
name phone
sam 7753457893
tom 7753457893
pop 7753457893
john 7753457893
How to find if all the columns in table A are present in table B or not. I tried using except but I am getting a compilation error "invalid no of columns for set operator input branches, expected 22, got 11 ".I used this query
"select * from table B
except
select * from table A".
Table A has 22 columns and table B has 11 columns. I need a query to know that all the columns in table B are in table A
Basically I want to know table B is a subset of table A or not.
You can use this query
SELECT ColumnFromB
FROM TableB
EXCEPT
SELECT ColumnFromA
FROM TableA
This will give you a list of records that are in B but not in A.
Then you can insert the result into a table variable, and check its COUNT
(if count= 0 'subset'
else is not subset).

Query for non sequential Id table to update values from a referenced table [duplicate]

This question already has answers here:
SQL update query using joins
(13 answers)
Closed 4 years ago.
I need to update a column in a table X with values that are written in another table Y. Mind you that there are gaps in the Id column as several/some rows were deleted. It starts with 63450 the Id column in table X, and it is not really sequential as shown below:
table X
Id Name Value
-------------------------------------------
63450 cmd NULL
63451 Jong NULL
63456 Xau-Min NULL
63457 bgf NULL
63458 tcr NULL
63459 cro NULL
63500 344453f NULL
63501 stackoverflow NULL
Table Y (parametrization)
Id Acronym Code
-------------------------------
1 cmd 545654
2 bgf 454565
3 cro 555555
4 rtg 465456
5 ert 546546
6 tcr 878787
Now after updating table X it should appear the following. It will update the vALUE in table X according to the matches in table Y...
table X after updating....
Id Name Value
-------------------------------------------
63450 cmd 545654
63451 Jong NULL
63456 Xau-Min NULL
63457 bgf 454565
63458 tcr 878787
63459 cro 555555
63500 344453f NULL
63501 stackoverflow NULL
if I try with
USE Database
DECLARE #counter int
SET #counter=(select count(*) from table_X)
WHILE #counter>0
BEGIN
UPDATE table_X
SET Value=(select Code
from table_Y b inner join table_X a on a.Name=b.Acronym
where a.Id= max(a.Id)-#counter+1)
SET #value=#value-1
END
it WILL not work as the Id is not sequential... how to achieve the updated table X as shown?
2nd: it would be nice to have a function to detect only letters (in the column Name of table X).. is there any in SQL? I only know to detect numeric values in strings: the isnumeric() function.
Thanks. :)
I think this is what you're after:
UPDATE X
SET [Value] = Y.Code
FROM TableX X
JOIN TableY Y ON X.[name] = Y.Acronym;
There's definitely no need for a loop here. In fact, using a looping structure in SQL is generally the worst thing to do for performance.
This is actually quite a simple query, in terms of SQL statements, so do you understand what it's doing?

Easiest way to update the ids of rows in sql server?

the primary key ID values in this table are being used in our 2 systems that were recently merged, however there is a large number of items in one of the systems that are pointing to the wrong id values, i need to update the ID(PK) values so that the 6 million existing items will be pointing to the correct row.
id like to update the id columns to the following:
ID
1 to 5
2 to 6
3 to 7
4 to 1
5 to 2
6 to 3
7 to 4
Well, assuming it is not an IDENTITY column (in which case you'll need to set IDENTITY_INSERT to on) then the following should work (see SQLFiddle for example)
UPDATE MyTable
SET ID =
CASE WHEN ID >= 4 SET ID - 3
ELSE ID + 4
END
Use update query with a case statement
Update tableName set PkId = Case PkId
When 1 then 5
When 2 then 6
When 3 then 7
When 4 then 1
When 5 then 2
When 6 then 3
When 7 then 4 End
Where PkId In (1,2,3,4,5,6,7)
If the values in your answer aer just a small subset of the values that need to be change (Do all 6 million need to change?), then you need to Create a mapping table that has the old incorrect value and the new correct value, and use that (with a join) instead of the case statement.
Update t set PkId = map.NewPkId
From tablename t
Join mappingTable m
On m.oldPkId = t.PkId