I have a MySql database with a Users table:
create table Users
(
Id varchar(255) charset utf8mb4 not null primary key,
ProfileId int auto_increment,
#other fields
);
ProfileId field is used as a foreign key for many tables. E.g.:
create table Fingerprints
(
Id int auto_increment primary key,
ProfileId int null,
constraint FK_Fingerprints_Users_ProfileId
foreign key (ProfileId) references Users (ProfileId)
);
I have two Users records and want to swap their ProfileIds without any other changes. How can I do it? I would prefer not to drop foreign key constrain because the database is on production and there are a lot of related tables where I have to do that.
Update:
The data is the following:
User1: ProfileId = 1,
User2: ProfileId = 2
#the other field doesn't matter
I want to swap their profileIds, so user1 contained user2's data from the related table by foreign key and vise versa.
Presumably, you don't want to change the foreign key relationships (they are not defined as cascading) I would suggest that you change the other columns:
update users u join
users u2
on (u2.profileid, u.profileid) in ( (#id1, #id2), (#id2, id1) )
set u.id = u2.id,
u.others = u2.others;
Related
I have table users
CREATE TABLE IF NOT EXISTS users(
id int AUTO_INCREMENT PRIMARY KEY,
user_id INTEGER NOT NULL UNIQUE,
goal VARCHAR(255) DEFAULT NULL,
age INTEGER DEFAULT NULL,
gender VARCHAR(255) DEFAULT NULL,
country VARCHAR(255) DEFAULT NULL,
city VARCHAR(255) DEFAULT NULL,
comment VARCHAR(255) DEFAULT NULL)
I want to create table friends. One key feature that is every user by default friend for itself.
This is my current statement
create table friends (user_id int, friend_id int, FOREIGN KEY (user_id) REFERENCES users (user_id), foreign key (friend_id) references users (user_id)) as select user_id from users;
update friends set shown_id = user_id;
I think it looks pretty kludgy, creating a table and changing it immediately, may be there a better way to implement it?
Another important note: the database loses connection after creating the friends table.
create table friends (user_id int, friend_id int, FOREIGN KEY (user_id) REFERENCES users (user_id), foreign key (friend_id) references users (user_id)) as select user_id from users;
ERROR: 2006: MySQL server has gone away
The global session got disconnected..
Attempting to reconnect to 'mysqlx://root#localhost:33060/test_db'....
The global session was successfully reconnected.
Don't know where shown_id came from, but I guess it's a typo.
Instead of populating only one column (user_id) of your friends table, you can add another user_id column to the select statement with friend_id alias. Immediate update query is not needed.
create table friends (
user_id int,
friend_id int,
foreign key (user_id) references users (user_id),
foreign key (friend_id) references users (user_id)
) as (
select user_id, user_id as friend_id
from users
);
Original answer https://dba.stackexchange.com/a/266893/208647
Issue:
I'm using PostgreSQL Database.
I have one table (Albums) to be linked to two other tables (Clients, Domains). So if you are Client or Domain you can have Album. But in Albums table owner can handle only single foreign key. How can I solve this issue?
Dream: Single Album can own only (1) Client or Domain. Need fix issue with foreign keys. Albums: id | owner (multiple foreign -> Clients:id or Domains:id) --> can not do this | name. I just need some smart rework.
Tables (now can have Album only Domain):
Albums
Clients
Domains
Albums (table with foreign key yet):
id | owner (foreign key -> Domains:id) | name
Clients:
id | first_name | last_name
Domains:
id | owner | name
Add 2 FK columns, and a CHECK constraint, to enforce only one of them is NOT NULL...
Something like this:
CREATE TABLE albums (
id serial PRIMARY KEY,
client_id integer,
domain_id integer,
name varchar(255) NOT NULL,
FOREIGN KEY (client_id) REFERENCES clients(id),
FOREIGN KEY (domain_id) REFERENCES domains(id),
CHECK ((client_id IS NULL) <> (domain_id IS NULL))
);
To query you can use something like this:
SELECT a.id, COALESCE(c.id, d.id) AS owner_id, COALESCE(c.name, d.name) AS owner_name,
a.name AS title
FROM albums a
LEFT JOIN clients c ON a.client_id = c.id
LEFT JOIN domains d ON a.domain_id = d.id
#e_i_pi's version
CREATE TABLE entities (
id serial PRIMARY KEY,
type integer, -- could be any other type
-- any other "common" values
);
CREATE TABLE client_entities (
id integer PRIMARY KEY, -- at INSERT this comes from table `entities`
name varchar(255) NOT NULL,
);
CREATE TABLE domain_entities (
id integer PRIMARY KEY, -- at INSERT this comes from table `entities`
name varchar(255) NOT NULL,
);
CREATE TABLE albums (
id serial PRIMARY KEY,
owner_id integer FOREIGN KEY REFERENCES entities(id), -- maybe NOT NULL?
name varchar(255) NOT NULL,
);
Query:
SELECT a.id, owner_id, COALESCE(c.name, d.name) AS owner_name, a.name AS title
FROM albums a
LEFT JOIN entities e ON a.owner_id = e.id
LEFT JOIN client_entities c ON e.id = c.id AND e.type = 1 -- depending on the type of `type`
LEFT JOIN domain_entities d ON e.id = d.id AND e.type = 2
Righto, so as suggested in the comment to the answer by #UsagiMiyamoto, there is a way to do this that allows declaration of entity types, with cascading. Note that this solution doesn't support unlimited entity types, as we need to maintain concrete FK constraints. There is a way to do this with unlimited entity types, but involves triggers and quite a bit of nastiness.
Here's the easy to understand solution:
-- Start with a test schema
DROP SCHEMA IF EXISTS "entityExample" CASCADE;
CREATE SCHEMA IF NOT EXISTS "entityExample";
SET SEARCH_PATH TO "entityExample";
-- We'll need this to enforce constraints
CREATE OR REPLACE FUNCTION is_entity_type(text, text) returns boolean as $$
SELECT TRUE WHERE $1 = $2
;
$$ language sql;
-- Unique entity types
CREATE TABLE "entityTypes" (
name TEXT NOT NULL,
CONSTRAINT "entityTypes_ukey" UNIQUE ("name")
);
-- Our client entities
CREATE TABLE clients (
id integer PRIMARY KEY,
name TEXT NOT NULL
);
-- Our domain entities
CREATE TABLE domains (
id integer PRIMARY KEY,
name TEXT NOT NULL
);
-- Our overaching entities table, which maintains FK constraints against clients and domains
CREATE TABLE entities (
id serial PRIMARY KEY,
"entityType" TEXT NOT NULL,
"clientID" INTEGER CHECK (is_entity_type("entityType", 'client')),
"domainID" INTEGER CHECK (is_entity_type("entityType", 'domain')),
CONSTRAINT "entities_entityType" FOREIGN KEY ("entityType") REFERENCES "entityTypes" (name) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "entities_clientID" FOREIGN KEY ("clientID") REFERENCES "clients" (id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "entities_domainID" FOREIGN KEY ("domainID") REFERENCES "domains" (id) ON DELETE CASCADE ON UPDATE CASCADE
);
-- Our albums table, which now can have one owner, but of a dynam ic entity type
CREATE TABLE albums (
id serial PRIMARY KEY,
"ownerEntityID" integer,
name TEXT NOT NULL,
CONSTRAINT "albums_ownerEntityID" FOREIGN KEY ("ownerEntityID") REFERENCES "entities"("id")
);
-- Put the entity type in
INSERT INTO "entityTypes" ("name") VALUES ('client'), ('domain');
-- Enter our clients and domains
INSERT INTO clients VALUES (1, 'clientA'), (2, 'clientB');
INSERT INTO domains VALUES (50, 'domainA');
-- Make sure the clients and domains are registered as entities
INSERT INTO entities ("entityType", "clientID")
SELECT
'client',
"clients".id
FROM "clients"
ON CONFLICT DO NOTHING
;
INSERT INTO entities ("entityType", "domainID")
SELECT
'domain',
"domains".id
FROM "domains"
ON CONFLICT DO NOTHING
;
If you don't like the idea of inserting twice (once in client, once in entites, for example) you can have a trigger on inserts in the clients table, or alternately create an insert function that inserts to both tables at once.
I'm trying my first hand at creating a mysql database for a simple blog. I'm having trouble understanding foreign keys and their appropriate relations. If someone can explain in "layman's" terms I'll be very happy.
I have a table called users that has the basics of fields (username, email, password etc) which I've created a user_type field and set it to INT. I've created the corresponding table called user_type and added two fields (one being the type_id = primary key and the other been the type = VARCHAR).
My question is:
Am I correct in understanding that I connect the two tables together by setting the foreign key link from the user_type INT in the users table to reference the type_id from the user_type table?
Your understanding is correct.
From SQL FOREIGN KEY Constraint
A FOREIGN KEY in one table points to a PRIMARY KEY in another table.
So in your example, the user_type id in table user_types would be the primary key, and the user_type int in table users would be the foreign key entry.
This enforces that an entry in table user_types has to exist before it can be used in table users.
You referencing from user to usertype:
n users have one user_type
If you create the table with an sql statement it should include something like this in the user part:
DROP TABLE IF EXISTS `user` ;
CREATE TABLE IF NOT EXISTS `user` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`username` VARCHAR(55) NOT NULL ,
`email` VARCHAR(55) NOT NULL ,
`password` VARCHAR(55) NOT NULL ,
`user_type` INT NOT NULL ,
PRIMARY KEY (`ID`) ,
INDEX `user_to_usertype_idx` (`user_type` ASC) ,
CONSTRAINT `user_to_usertype`
FOREIGN KEY (`user_type` )
REFERENCES `user_type` (`type_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
You have to create user_type before you create user, otherwise you will get a failure.
I have 2 tables, customers and affiliates. I need to make sure that customers.email and affiliates.email are exclusive. In other words, a person cannot be both a customer and an affiliate. It's basically the opposite of a foreign key. Is there a way to do this?
You can use a table that stores emails and have unique constrain on the email, and reference that table from the customer and affiliate. (still need to ensure that there are no 2 records referencing the same key)
You can use trigger before insert and before update to check if the email is not present.
Or you can leave this validation to the application logic - not in the database, but in the applicationc ode.
There is no key you can do this with, but it sounds like you shouldn't be using two tables. Instead, you can have one table with either customer/affiliate data (that needs to be unique in this table) and another table that has the type (customer/affiliate).
CREATE TABLE People (
pplid,
pplEmail,
ptid,
UNIQUE KEY (pplEmail)
)
CREATE TABLE PeopleType (
ptid,
ptType
)
INSERT INTO PeopleType VALUES (1, 'affiliates'), (2, 'customers');
You can try the following.
Create a new table, which will be a master for customers and affiliates:
CREATE TABLE party
(
id int not null auto_increment primary key ,
party_type enum('customer','affiliate') not null,
email varchar(100),
UNIQUE (id,party_type)
);
--Then
CREATE TABLE customer
(
....
party_id INT NOT NULL,
party_type enum('customer') NOT NULL DEFAULT 'customer',
PRIMARY KEY (party_id,party_type)
FOREIGN KEY (party_id,party_type) REFERENCES party(id,party_type)
);
CREATE TABLE affiliates
(
....
party_id INT NOT NULL,
party_type enum('affiliate') NOT NULL DEFAULT 'affiliate',
PRIMARY KEY (party_id,party_type)
FOREIGN KEY (party_id,party_type) REFERENCES party(id,party_type)
)
-- enum is used because mysql still doesn't have CHECK constraints
This way each party can be only of one type
I am new to databases, but I have gone over some tutorials and learned most of the essentials (I am a long time programmer). However, I need some help getting around the limitations of relational databases. If I have a picture I can create a simple table for it as such
"CREATE TABLE picture(
file VARCHAR(150),
rating INT
)";
If I want to keep track of who rates for the picture, I can either hard code a preset number of voters like so (in this example 3 anonymous votes)
"CREATE TABLE picture(
file VARCHAR(150),
rating INT,
vote1 INT,
vote2 INT,
vote3 INT
)";
Or for an unlimited number I can create a new table as such
"CREATE TABLE ratingTemplate
(
rater INT,
rating INT
)";
But for every picture entry in the picture table I want to have a reference to this entire ratingTemplate table. Is there any proper way to use foreign keys to achieve this? Currently I am micromanaging it by creating new ratingTemplate tables and making sure to store their names in the corresponding picture table entry.
Yes, you would have to have a table that keeps references to picture table as well as user table.
CREATE TABLE IF NOT EXISTS PICTURE (
PICTURE_ID BIGINT NOT NULL AUTO_INCREMENT,
FILE VARCHAR(250),
PRIMARY KEY (PICTURE_ID)
);
CREATE TABLE IF NOT EXISTS USER (
USER_ID BIGINT NOT NULL AUTO_INCREMENT,
--....REST OF COLUMNS HERE...
PRIMARY KEY(USER_ID)
);
CREATE TABLE IF NOT EXISTS PICTURE_RATING (
RATING_ID BIGINT NOT NULL AUTO_INCREMENT,
PICTURE_ID BIGINT NOT NULL,
USER_ID BIGINT NOT NULL,
RATING DOUBLE,
PRIMARY KEY (RATING_ID),
FOREIGN KEY (PICTURE_ID) REFERENCES PICTURE(PICTURE_ID),
FOREIGN KEY (USER_ID) REFERENCES USER(USER_ID)
);
You have not identified the primary key for the 'picture' table, but as presented the primary key would appear to be the 'file' column. You would need to add a column to the 'ratingTemplate' table named 'file' that would also be be varchar(150. Your primary key in the 'ratingTemplate' would be a combination of 'file' and 'rater'. The 'file' column in the 'ratingTemplate' table would be a foriegn key to the 'file' column int he 'picture' table.
Sample Query:
SELECT picture.file, rater, rating
FROM picture INNER JOIN ratingTemplate ON picture.file = ratingTemplate.file
WHERE picture.file = 'filenameiwant'
Another approach would be to add a surrogate primary key to the 'picture' table.
Perhaps named 'FileId' as an integer. In that case, you would use the 'FileId' column in the 'ratingTemplate' as the foriegn key instead of 'file'. For large data sets this would execute faster and use less space.
Sample query:
FROM picture INNER JOIN ratingTemplate ON picture.FileId = ratingTemplate.FileId
WHERE picture.FileId = 257