primary key constraint error when doing an update - sql

I am having a bit of challenge doing mass update in SQL server. I have a table with composite primary key( studentid,login,pass). They have a common login and password as they are in a group. I m doing an (again all same login and pass) update and setting their login and pass to new values where the field, class group =x.But I get a duplicate primary key violation error. Any idea why?
Thanks

Given that you have a weird primary key, it's easy to see how it can be violated. For example, say student 1 has two rows in the table:
studentid login pass group
1 bobama reallyborninkenia politician
1 bobama2 raisetaxes politician
And say you update the group politician:
update StudentTable
set login = 'bobama'
, pass = 'justpwndromney'
where [group] = 'politician'
Then you'd get a primary key violation, since there would be two rows with the same (studentid, login, pass) combination.
If that is weird, that's because your primary key is weird. I'd expect the primary key to be just (studentid).

well clearly there is a clash, you are are creating a studentid/login/password combination that exists in the table already. This query should show you where the existing rows that clash with your proposed changes are:
select t.* from [your-table] t
join (select * from [your-table] where [class-group] = x) proposed-change
on proposed-change.[studentid] = [t.studentid]
where t.login = 'proposed-login' and t.password = 'proposed-password'

Related

wierd case of 'unique' constraint (possible case for exclusion) | Postgres

I have a question regarding constraint(unique or exclusion in this case I guess). I cant get my head around this simple case:
For example I have this simplified version of a table:
create table user
(
id serial not null
username varchar(30) not null
constraint user_username_key
unique,
is_active boolean not null,
company_id integer not null
constraint company_user_company_company_company_id
references company_company
deferrable initially deferred
I would like to create such constraint to satisfy following conditions:
If we have at least one (or possible few records) referencing same company_id (lets say = 3) that we must(it should exists) have one and only one username that ends on ‘-support’ (lets say ‘user1-support’) with is_active = True.
Wrong scenarios:
• we have one or more records but there are no any username that ends on `‘-support’` amoung this records
• we have one or more records and we have multiple usernames that ends on `‘-support’` amoung this records
If we have only one entry – then username should be ended with ‘-support’
Thanks
Sorry if question is naive
postgres 11 version
Filtered unique index could be used:
CREATE UNIQUE INDEX idx ON "user"
(company_id,(CASE WHEN username LIKE '%-support' THEN 'support' ELSE username END))
WHERE is_Active = True;
db<>fiddle demo

How to insert into a table if it violates a foreign key constraint

I am working on a script that moves data between two databases.
I am moving a table of Phone Numbers. Each Phone Number is for a user.
The problem is that each Phone Number entry references a User with a User ID. Some of these users do not exist anymore, so when I try to insert, it returns a foreign key constraint violation.
insert or update on table "phone_numbers" violates foreign key constraint "fk3843uenfej83jf32wde"
user_id = 10 is not present in table users
However, I can't go and delete each single user reference as there are thousands of references.
So what would be the best way to approach it?
Should I simply remove the foreign key constraint?
Phone numbers that belong to non existent users are termed “orphaned” data.
Either clean up orphaned data in the source data (orphaned data shouldn’t exist):
delete from phone_number
where not exists (select * from user where id = user_id)
Or don’t select them when exporting:
select p.*
from phone_number p
join user u on u.id = p.user_id
I would not remove the constraint, as it can have impacts on other things (application ? report ? Whatever).
So the question is wHhat do you need ?
Insert all ph. numbers including the ones without users
Insert only ph. numbers with users associated
In any case load your data to a 'temp' table call, temp_phones, without any constraint.
In case 1 migrate data to phone_numbers making userid = null if the user is not present anymore. You can do it with an "easy" query
In case 2 migrate data to phone_numbers only when the userid of the record is found in your user table, also this can be done with a query
You can perform both processes also after having migrate the data. In this case you should disable\remove the constraint, update the userid according to the proposed rules, then recreate the constraint

Update trigger old values natural key

I have an accounts table with the account owner as the primary key. In the update trigger, I want to update some accounts to new owners. Since this table doesn't have an id field, how do I use the inserted/updated tables in the trigger? DB is sql server 2008.
CREATE TRIGGER accounts_change_owner on accounts AFTER INSERT
AS BEGIN
MERGE INTO accounts t
USING
(
SELECT *
FROM inserted e
INNER JOIN deleted f ON
e.account_owner = f.account_owner ---this won't work since the new account owner value is diff
) d
ON (t.account_owner = d.account_owner)
WHEN MATCHED THEN
UPDATE SET t.account_owner = d.account_owner
END
I think I understood your question, but I am not sure. You want to be able update account owner name in one table and to have this update propagated to the referencing tables?
If so you don't really need a trigger, you can use on update cascade foreign key.
Like this:
create table AccountOwner
(
Name varchar(100) not null
constraint PK_AccountOwner primary key
)
create table Account
(
AccountName varchar(100) not null,
AccountOwnerName varchar(100) not null
constraint FK_Account_AccountOwnerName references AccountOwner(Name) on update cascade
)
insert AccountOwner values('Owner1')
insert Account values('Account1', 'Owner1')
Now if I update table AccountOwner like this
update AccountOwner
set Name = 'Owner2'
where Name = 'Owner1'
it will automatically update table 'Account'
select *
from Account
AccountName AccountOwnerName
----------- -----------------
Account1 Owner2
I think you need to modify the design of your table. Recall that the three attributes of a primary key are that the primary key must be
Non-null
Unique
Unchanging
(If the primary key consists of multiple columns, all columns must follow the rules above). Most databases enforce #1 and #2, but the enforcement of #3 is usually left up to the developers.
Changing a primary key value is a classic Bad Idea in a relational database. You can probably come up with a way to do it; that doesn't change the fact that it's a Bad Idea. Your best choice is to add an artificial primary key to your table, put NOT NULL and a UNIQUE constraints on the ACCOUNT_OWNER field (assuming that this is the case), and change any referencing tables to use the artificial key.
The next question is, "What's so bad about changing a primary key value?". Changing the primary key value alters the unique identifier for that particular data; if something else is counting on having the original value point back to a particular row, such as a foreign key relationship, after such a change the original value will no longer point where it's supposed to point.
Good luck.

a sql question about linking tables

I wonder why these statements are not the same (the first one worked for me)
AND user_thread_map.user_id = $user_id
AND user_thread_map.thread_id = threads.id
AND user_thread_map.user_id = users.id
AND user_thread_map.thread_id = threads.id
AND users.id = $user_id
Shouldn't they be the same? In the 2nd one I linked all the tables in the first 2 lines, then I tell it to select where users.id = $user_id.
Can someone explain why the 2nd statement doesn't work? Because I thought it would.
Assuming you're getting no rows returned (you don't really say what the problem is, so I'm guessing a bit here), my first thought is that there are no rows in users where id is equal to $user_id.
That's the basic difference between those two SQL segments, the second is a cross-join of the user_thread_map, threads and users tables. The first does not join with users at all, so that's where I'd be looking for the problem.
It appears that your user_thread_map table is a many-to-many relationship between users and threads. If that is true, are you sure you have a foreign key constraint between the ID fields in that table to both corresponding other tables, something like:
users:
id integer primary key
name varchar(50)
threads:
id integer primary key
thread_text varchar(100)
user_thread_map:
user_id integer references users(id)
thread_id integer references threads(id)
If you have those foreign key constraints, it should be impossible to end up with a user_thread_map(user_id) value that doesn't have a corresponding users(id) value.
If those constraints aren't there, a query can tell you which values need to be fixed before immediately adding the constraints (this is important to prevent the problem from re-occurring), something like:
select user_thread_map.user_id
from user_thread_map
left join users
on user_thread_map.user_id = users.id
where users.id is null
The first one would select records from table user_thread_map with user_id = $user_id, irrespective of whether a record in table user existed with that id. The second query would only return something if the related record in user is found.

Updating foreign key values

I have a database application in which a group is modeled like this:
TABLE Group
(
group_id integer primary key,
group_owner_id integer
)
TABLE GroupItem
(
item_id integer primary key,
group_id integer,
group_owner_id integer,
Foreign Key (group_id, group_owner_id) references Group(group_id, group_owner_id)
)
We have a multi field foreign key set up including the group_owner_id because we want to ensure that a GroupItem cannot have a different owner than the Group it is in. For other reasons (I don't think I need to go into detail on this) the group_owner_id cannot be removed from the GroupItem table, so just removing it is not an option.
My big problem is if i want to update the group_owner_id for the entire group, I'm writing code like this (in pseudo code):
...
BeginTransaction();
BreakForeignKeys(group_items);
SetOwnerId(group, new_owner_id);
SaveGroup(group);
SetOwnerId(group_items, new_owner_id);
SetForeignKeys(group_items, group);
SaveGroupItems(group_items);
CommitTransaction()
...
Is there a way around doing this? It seems a bit clunky. Hopefully, I've posted enough detail.
Thanks.
Does SQL Server not support UPDATE CASCADE? :-
Foreign Key (group_id, group_owner_id)
references Group(group_id, group_owner_id)
ON UPDATE CASCADE
Then you simply update the Group table's group_owner_id.
Tony Andrew's suggestion works. For example, say you'd like to change the owner of group 1 from 2 to 5. When ON UPDATE CASCADE is enabled, this query:
update [Group] set group_owner_id = 5 where group_id = 1
will automatically update all rows in GroupItem.
If you don't control the indexes and keys in the database, you can work around this by first inserting the new group, then modifying all rows in the dependant table, and lastly deleting the original group:
insert into [Group] values (1,5)
update [GroupItem] set group_owner_id = 5 where group_id = 1
delete from [Group] where group_id = 1 and group_owner_id = 2
By the way, GROUP is a SQL keyword and cannot be a table name. But I assume your real tables have real names so this is not an issue.
You might try to add an update rule to cascade changes.
Microsoft Links
Foreign Key Relationships Dialog Box (see Update Rule)
Grouping Changes to Related Rows with Logical Records