How can I fill empty table rows which references another table's column ID? - sql

I want to fill out empty notification_settings for each user that already exists. IDs (PKs) are auto-generated by Hibernate in each table. Here is the user Table :
CREATE TABLE lottery_user (
id int8 not null,
email varchar(255) not null,
password varchar(255) not null,
notification_settings_id int8,
role varchar (50) default 'USER',
registry_date TIMESTAMP default now(),
primary key (id)
ADD CONSTRAINT FK_USER_TO_NOTIFICATION_SETTINGS
FOREIGN KEY (notification_settings_id) REFERENCES notification_settings
);
And here is the notification_settings table which I need to fill out for users that don't have it filled out for them.
CREATE TABLE notification_settings (
id int8 not NULL ,
test1_events bool DEFAULT TRUE ,
test2_events bool DEFAULT TRUE ,
test3_events bool DEFAULT TRUE ,
test4_events bool DEFAULT TRUE ,
PRIMARY KEY (id)
);
Basically, I need to use "INSERT INTO notification_settings (test1_events, test2_events, test3_events, test4_events) VALUES (True, True, True, True)" something similar to that. And of course, condition should be something like this "where these rows are empty for users". I can't seem to get Syntax right.
BIG NOTE: SQL code is for presentation purpose, so you can have an idea what kind of tables I have. I just need to get INSERT script right. Tables are working fine, just need to generate notification_settings values for users that already exist.
Another Note: Using Flyway, so it's not just about Hibernate. If that has to do with anything.

Are you just looking for:
INSERT INTO notification_settings (id)
SELECT id
FROM user
WHERE id NOT IN (SELECT id FROM notifiation_settings)
You might be looking to insert into an identity field:
SET IDENTITY_INSERT my_table ON

Since your foreign key constraint goes from notification_settings to user, the condition "where these rows are empty for user X" does not apply to your schema. On the other hand - "I want to fill out empty notification_settings for each user that already exists" can be done by using an insert...select construct:
set #rank=0
select #maxid = max(id) from notification_settings
insert into notification_settings (id)
select #maxid + #rank:=#rank+1 as rank
from user
where notification_settings_id is null
What is interesting is how you put those newly generated IDs back into the user table. Homework assignment for next time :)

INSERT INTO notification_settings (id)
SELECT u.id
FROM user u
WHERE
not exists (SELECT * FROM notifiation_settings ns where ns.id=i.id)

I will answer my own question how I dealt with it. Firstly, I insert IDs into notification_settings id, then I get those IDs and set them into lottery_user table's FK (notification_settings_id). Then I just delete unneeded IDs. Yea not perfect but it works.
INSERT INTO notification_settings (id) select lu.id from lottery_user lu where lu.id not in(select ns.id from notification_settings ns);
update lottery_user lu set notification_settings_id = (select ns.id from notification_settings ns where ns.id = lu.id) where lu.notification_settings_id is null;
delete from notification_settings ns where not exists (select * from lottery_user lu where lu.notification_settings_id = ns.id);
Also, script to Alter Sequence for new Lottery_user entities.
do $$
declare maxid int;
begin
select max(id) from lottery_user into maxid;
IF maxid IS NOT NULL THEN
EXECUTE 'ALTER SEQUENCE notification_settings_seq START with '|| maxid;
END IF;
end;
$$ language plpgsql;

Related

Update and log only changed rows with SQL in SQLite

I am writing an application/script in R that updates a SQLite database.
My apologies - I am not experienced with this.
My table consists of 4 fields Id,Name,LVL,Notes:
CREATE TABLE members (
Id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL,
LVL INTEGER NOT NULL,
Notes TEXT
);
INSERT INTO members (Name,LVL,Notes)
VALUES ('Jean',12,'First stage'),
('Jacques',1,'Second stage'),
('Amelie',1,'Second stage'),
('Louis',13,'Some other note altogether')
;
I want to check it against another table tmp
CREATE TABLE tmp (
Name TEXT NOT NULL,
LVL INTEGER NOT NULL,
Notes TEXT
);
INSERT INTO tmp (Name,LVL,Notes)
VALUES ('Jean',13,'First stage'),
('Jacques',1,'Second stage'),
('Amelie',1,'Third stage'),
('Louis',14,'Fourth stage')
;
and if there are changes in LVL and/or Notes fields (as LVL for Jean and Louis and Notes for Amelie and Louis) I want to update the members table with new values after I record the previous values (as whole rows) with a timestamp in member_changes table.
What would be the minimal set of queries to achieve this?
And what is the better design of the member_changes table? Would it be the same as members but with added rowID as primary key and timestamp fields? And naturally memberID would allow duplicates.
Many thanks,
Rob
SYNOPSIS of expanded answer
Thanks to #forpas kind answer I put this small system together with 2 additional triggers. New information comes in via tmp table. Member names are presumed to be unique; possibly primary key on members.Id was not needed. Nevertheless:
-- CREATE members table for current guild members
-- Id is prim key and Name has unique index
CREATE TABLE members (
Id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL UNIQUE,
LVL INTEGER NOT NULL,
Notes TEXT
);
-- SAMPLE DATA
INSERT INTO members (Name,LVL,Notes) VALUES
('Jean',12,'First stage'),
('Jacques',1,'Second stage'),
('Amelie',1,'Second stage'),
('Louis',13,'Some other note altogether');
-- LOG table to see membership changes over time
CREATE TABLE members_changes (
timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
Id INTEGER REFERENCES members(Id),
Name TEXT NOT NULL,
LVL INTEGER NOT NULL,
Notes TEXT
);
-- TABLE through which the updates will come in via rvest
-- presumed cannot contain duplicate names
CREATE TABLE tmp (
Name TEXT NOT NULL UNIQUE,
LVL INTEGER NOT NULL,
Notes TEXT
);
-- TRIGGERS (3)
-- (1) UPDATES MEMBERS if insertion in tmp shows changes
-- also LOGS this change in members_changes
CREATE TRIGGER IF NOT EXISTS tr_insert_tmp AFTER INSERT ON tmp
BEGIN
INSERT INTO members_changes(Id,Name,LVL,Notes)
SELECT Id,Name,LVL,Notes
FROM members
WHERE Name = NEW.NAME AND (LVL IS NOT NEW.LVL OR Notes IS NOT NEW.Notes);
UPDATE members
SET LVL = NEW.LVL, Notes = NEW.Notes
WHERE Name = NEW.Name AND (LVL IS NOT NEW.LVL OR Notes IS NOT NEW.Notes);
END;
-- (2) LOGS DELETIONS from members
CREATE TRIGGER IF NOT EXISTS tr_delete_members BEFORE DELETE ON members
BEGIN
INSERT INTO members_changes(Id,Name,LVL,Notes)
SELECT Id,Name,LVL,Notes || " :Deleted"
FROM members
WHERE Name = OLD.Name;
END;
-- (3) LOGS INSERTS into members (new members)
CREATE TRIGGER IF NOT EXISTS tr_insert_members AFTER INSERT ON members
BEGIN
INSERT INTO members_changes(Id,Name,LVL,Notes)
SELECT Id,Name,LVL,Notes || " :Inserted"
FROM members
WHERE Name = NEW.Name;
END;
-- this shows all defined triggers
select * from sqlite_master where type = 'trigger';
-- QUERIES to be run from the script after tmp is updated (b,c,d)
-- ADD NEW MEMBERS
-- it should mostly fail (changes are slow and few)
-- this is logged via tr_insert_members
INSERT OR IGNORE INTO members(Name,LVL,Notes) SELECT Name, LVL, Notes FROM tmp;
-- DELETE OLD MEMBERS
-- logged via tr_delete_members
DELETE FROM members WHERE Name NOT IN (SELECT Name FROM tmp);
-- EMPTY tmp at the end of the script run
DELETE FROM tmp;
When application runs the only queries that need to be called are:
a) the one which populates tmp (from dataframe gathered by rvest)
b) query to add new members from tmp
c) query to delete members not in tmp
d) query to empty tmp
This is thanks to database setup kindly suggested by #forpas. I had never used triggers and finally made some sense of them. Very helpful for logging changes.
A proper design for members_changes is this:
CREATE TABLE members_changes (
timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
Id INTEGER REFERENCES members(Id),
Name TEXT NOT NULL,
LVL INTEGER NOT NULL,
Notes TEXT
);
The column timestamp's default value is the current timestamp.
You need an AFTER INSERT trigger for the table tmp, so that for every inserted row in tmp, the respective row from members will be inserted in members_changes (if any value of LVL or Notes is different) and after that the new row from tmp will update the row of members:
CREATE TRIGGER IF NOT EXISTS tr_insert_tmp AFTER INSERT ON tmp
BEGIN
INSERT INTO members_changes(Id,Name,LVL,Notes)
SELECT Id,Name,LVL,Notes
FROM members
WHERE Name = NEW.NAME AND (LVL IS NOT NEW.LVL OR Notes IS NOT NEW.Notes);
UPDATE members
SET LVL = NEW.LVL, Notes = NEW.Notes
WHERE Name = NEW.Name AND (LVL IS NOT NEW.LVL OR Notes IS NOT NEW.Notes);
END;
See the demo.

Postgres: Want to SELECT data when user exists, else INSERT user

Still getting the hang of PostgreSQL (Using PostgreSQL-12, so any advice is very much appreciated.
I have an application that allows the user to save and create playlists of songs.
My tables are: users, playlists, songs
Then I have two junction tables: user_playlist, playlist_song
I have a query that when given a userid will return all of the songs, from that user's first playlist (app defaults to first playlist on login), and it currently works how I want it to.
My next issue to tackle is that I want to now combine that query, with a second, that would add the userid to the user table if it didn't currently exist.
So the flow would be user logins in, then on login a userid is sent to my db.
In my database I want to check if that userid already exists, if it does I want the SELECT query that return songs to execute, but if that userid does not exist, I want to insert the userid into my user table
I've read about 10 StackOverflow solutions trying to tweak them to work for me, but haven't had any luck. I'm not sure if I should post all of the things I've already tried or not.
$$ BEGIN
IF EXISTS (SELECT 1 FROM users WHERE userid = '1') THEN
SELECT
s.songid,
s.title,
s.artists,
s.album,
s.year,
s.duration,
s.url,
ps.songOrder
FROM
playlist_song ps
JOIN
songs s
ON
ps.songid = s.songid
JOIN
playlists p
ON
ps.playlistid = p.playlistid
WHERE
p.playlistid = (
SELECT
p.playlistid
FROM
user_playlist up
JOIN
playlists p
ON
up.playlistid = p.playlistid
JOIN
users u
ON
up.userid = u.userid
WHERE
u.userid = '1'
LIMIT 1
)
ORDER BY ps.songOrder;
ELSE
INSERT INTO users (userid, username) VALUES ('1', 'Haley')
ON CONFLICT DO NOTHING;
END IF;
END $$;
This is the error it is currently giving me when I test it in PG admin:
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function inline_code_block line 4 at SQL statement
SQL state: 42601
So I then added RETURN to my SELECT and the error changed to
LINE 5: RETURN (SELECT
^
SQL state: 42804
Character: 98
Adding RETURN QUERY gave the error was Cannot use return query in a non-setof function
Adding RETURN SETOF gave the error was RETURN cannot have a parameter in function returning void
I've been stuck on this for a day and a half and at this point and don't want to break it up into multiple calls to the db unless it's not possible (my pride needs to squash this bugger)
I can't tell you how much your help will be appreciated! Thanks in advance
EDIT: Here are my tables
CREATE TABLE IF NOT EXISTS users (
userid TEXT NOT NULL,
username TEXT NOT NULL,
CONSTRAINT u_id_pk PRIMARY KEY (userid)
);
CREATE TABLE IF NOT EXISTS playlists (
playlistid SERIAL NOT NULL,
playlistname TEXT NOT NULL,
CONSTRAINT p_id_pk PRIMARY KEY (playlistid)
);
CREATE TABLE IF NOT EXISTS songs (
songid SERIAL NOT NULL,
url TEXT,
href TEXT,
title TEXT,
artists TEXT,
album TEXT,
year integer,
duration integer,
CONSTRAINT s_pk PRIMARY KEY (songid)
);
CREATE TABLE IF NOT EXISTS user_playlist (
userid TEXT,
playlistid INTEGER,
CONSTRAINT u_up_fk FOREIGN KEY (userid) REFERENCES users(userid),
CONSTRAINT p_up_fk FOREIGN KEY (playlistid) REFERENCES playlists(playlistid)
);
CREATE TABLE IF NOT EXISTS playlist_song (
playlistid INTEGER,
songid INTEGER,
songOrder INTEGER,
CONSTRAINT p_ps_fk FOREIGN KEY (playlistid) REFERENCES playlists(playlistid),
CONSTRAINT s_ps_fk FOREIGN KEY (songid) REFERENCES songs(songid)
);
Next attempt:
CREATE TYPE songs_type AS (
songid integer,
title character varying(25),
artists character varying(25),
album character varying(25),
year integer,
duration integer,
url character varying(25),
songOrder integer
);
CREATE OR REPLACE FUNCTION func() RETURNS songs_type AS
$$
DECLARE results_record songs_type;
BEGIN
IF EXISTS (SELECT 1 FROM auxium.users WHERE userid = '1') THEN
SELECT
s.songid,
s.title,
s.artists,
s.album,
s.year,
s.duration,
s.url,
ps.songOrder
INTO
results_record.songid,
results_record.title,
results_record.artists,
results_record.album,
results_record.year,
results_record.duration,
results_record.url,
results_record.songOrder
FROM
auxium.playlist_song ps
JOIN
auxium.songs s
ON
ps.songid = s.songid
JOIN
auxium.playlists p
ON
ps.playlistid = p.playlistid
WHERE
p.playlistid = (
SELECT
p.playlistid
FROM
auxium.user_playlist up
JOIN
auxium.playlists p
ON
up.playlistid = p.playlistid
JOIN
auxium.users u
ON
up.userid = u.userid
WHERE
u.userid = '1'
LIMIT 1
)
ORDER BY ps.songOrder;
ELSE
INSERT INTO auxium.users (userid, username) VALUES ('1', 'Haley')
ON CONFLICT DO NOTHING;
END IF;
return results_record;
END;
$$
LANGUAGE plpgsql;
Create type and then return it.
I have created users(userid,username) table and then created type with same schema as i am selecting the same. You will have to change it to the columns you are selecting(while creating TYPE).
It is working fine.
CREATE TYPE users_type AS (userid integer,username character varying(10));
CREATE OR REPLACE FUNCTION fun() RETURNS users_type AS
$$
DECLARE result_record users_type;
BEGIN
IF EXISTS (SELECT 1 FROM users WHERE userid = 1) THEN
SELECT userid,username into result_record.userid,result_record.username from users;
ELSE
INSERT INTO users (userid, username) VALUES (1, 'Haley');
END IF;
return result_record;
END;
$$
LANGUAGE plpgsql;

How to add values in one table automatically when a condition is true

So, Here is the condition.
I have a User_tbl whose code is as follow
CREATE TABLE Users_tbl (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
username TEXT,
password TEXT,
user_type INT
);
user_type is either 0,1 or 2 .. If it is 0 then it is player , 1 is for coach and 2 is for audience.
Now, I want to create a new table which has lists of coach inside it . Whose schema will be
CREATE TABLE coach_tbl(
coach_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
username TEXT,
password TEXT
)
and what I need is that, when the entry which is placed in Users_tbl has user_type =1 then it should Trigger one other query which will create an entry in coach_tbl and fill the columns. It should happen dynamically .
The following TRIGGER would accomplish what you want :-
CREATE TRIGGER setup_coach
AFTER INSERT ON Users_tbl
WHEN new.user_type = 1
BEGIN
INSERT INTO coach_tbl (username, password) VALUES(new.username,new.password);
END
;
The following was used for testing the above :-
DROP TABLE IF EXISTS Users_tbl;
CREATE TABLE IF NOT EXISTS Users_tbl (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
username TEXT,
password TEXT,
user_type INT
);
DROP TABLE IF EXISTS coach_tbl;
CREATE TABLE IF NOT EXISTS coach_tbl(
coach_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
username TEXT,
password TEXT
);
CREATE TRIGGER setup_coach
AFTER INSERT ON Users_tbl
WHEN new.user_type = 1
BEGIN
INSERT INTO coach_tbl (username, password) VALUES(new.username,new.password);
END
;
INSERT INTO Users_tbl (username, password,user_type)
VALUES
('Fred','fred1234',0),
('Bert','bert1234',1),
('Harold','harold1234',0),
('Alan','alan1234',1);
The result being :-
Supplementary (aka Why not the above)
Storing the exact same values. i.e. duplicating them, is contrary to normalisation and could lead to issues. e.g. if (using the above) "Bert"'s name or "password" changed you'd have to change it in two places. As it stands there is no need to duplicate this data as it would be easily available
For example, if you wanted to list the coaches you could use :-
SELECT username FROM coach_tbl;
Using the following, though, returns exactly the same but without the additional table :-
SELECT username FROM Users_tbl WHERE user_type = 1;
Supposing you had coach specific information say for example the number of times coaching then you could have an additional table such as :-
CREATE TABLE IF NOT EXISTS coaching_information
(
user_id_reference INTEGER REFERENCES Users_tbl(id),
number_of_times_coaching INTEGER DEFAULT 0
)
;
Along with a TRIGGER to automatically add default coaching information :-
CREATE TRIGGER autoadd_coaching_information_entry
AFTER INSERT ON Users_tbl
WHEN new.user_type = 1
BEGIN
INSERT INTO coaching_information
(user_id_reference)
VALUES (new.id)
;
END
;
Note! no need to set the number_of_times_coaching column as it will default to 0.
Assuming that all TABLES have been emptied then using (again):-
INSERT INTO Users_tbl (username, password,user_type)
VALUES
('Fred','fred1234',0),
('Bert','bert1234',1),
('Harold','harold1234',0),
('Alan','alan1234',1);
results in :-
2 refers to Bert, 4 to Alan
You could then list all coaches who have not coached (chosen for laziness of not having to update coaching inforamtion) :-
SELECT 'Coach '||username||' is up for a coaching experience.' AS coaching_needed
FROM coaching_information
JOIN Users_tbl ON Users_tbl.id = coaching_information.user_id_reference
WHERE coaching_information.number_of_times_coaching < 1
The result would be :-
Say Bert changed name to Charles e.g. using UPDATE Users_tbl SET username = 'Charles' WHERE username = 'Bert';
Then just with the 1 change the results from the above query would be :-
The full SQL used for testing the above was :-
DROP TABLE IF EXISTS coach_tbl;
DROP TABLE IF EXISTS Users_tbl;
CREATE TABLE IF NOT EXISTS Users_tbl (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
username TEXT,
password TEXT,
user_type INT
);
DROP TRIGGER IF EXISTS setup_coach; -- get rid of defunct TRIGGER
CREATE TABLE IF NOT EXISTS coaching_information
(
user_id_reference INTEGER REFERENCES Users_tbl(id) ON DELETE CASCADE,
-- Note ON DELETE CASCADE will automatically delete a coach should
-- the coach's User_tbl entry be deleted i.e. the deletion is propoagted
-- to the children of the parent.
-- (could also use ON UPDATE CASCADE but unlikely to change the underlying id)
number_of_times_coaching INTEGER DEFAULT 0
)
;
DROP TRIGGER IF EXISTS autoadd_coaching_information_entry;
CREATE TRIGGER autoadd_coaching_information_entry
AFTER INSERT ON Users_tbl
WHEN new.user_type = 1
BEGIN
INSERT INTO coaching_information
(user_id_reference)
VALUES (new.id)
;
END
;
INSERT INTO Users_tbl (username, password,user_type)
VALUES
('Fred','fred1234',0),
('Bert','bert1234',1),
('Harold','harold1234',0),
('Alan','alan1234',1)
;
--
-- Note! oncommmenting this will change Bert's name to Charles
--UPDATE Users_tbl SET username = 'Charles' WHERE username = 'Bert';
--
SELECT 'Coach '||username||' is up for a coaching experience.' AS coaching_needed
FROM coaching_information
JOIN Users_tbl ON Users_tbl.id = coaching_information.user_id_reference
WHERE coaching_information.number_of_times_coaching < 1

Firebird autoIncrement issue

I've created Customers Table through following code :
CREATE TABLE CUSTOMERS (
ID INTEGER DEFAULT 1 NOT NULL,
"NAME" VARCHAR(30) CHARACTER SET UTF8 COLLATE UTF8,
"LASTNAME" VARCHAR(30) CHARACTER SET UTF8 COLLATE UTF8);
ALTER TABLE CUSTOMERS ADD PRIMARY KEY (ID);
SET TERM ^ ;
CREATE TRIGGER BI_CUSTOMERS_ID FOR CUSTOMERS
ACTIVE BEFORE INSERT
POSITION 1
AS
BEGIN
IF (NEW.ID IS NULL) THEN
NEW.ID = GEN_ID(CUSTOMERS_ID_GEN, 1);
END^
SET TERM ; ^
But when I inserting second row like :
insert into Customers(Name,LastName) values('Hamed','Kamrava');
It gets below error :
Violation of PRIMARY or UNIQUE KEY constraint "INTEG_2" on table "CUSTOMERS".
id is a primary key with default value 1.
In the first record, since you have not explicitly mentioned the value of id, it has inserted with 1. But you cannot have any other records with id = 1 since id is a Primary Key.
Use the statement:
insert into Customers(id, Name, LastName) values (2, 'Hamed', 'Kamrava');
This should insert the record. If you do not want to hardcode the value of ID for each row, suggest you to create a sequence and then during the insert, use,
insert into Customers(id, Name, LastName) values (nextval('<seq_name>'), <name>, <lastname>);
Since your trigger code is
IF (NEW.ID IS NULL) THEN
NEW.ID = GEN_ID(CUSTOMERS_ID_GEN, 1);
and, as #Orangecrush posted, you set a default value of 1, a unique id is never generated. So you should try to omit the default value in the ddl.

How can I insert a set of child records while updating the parent?

I'm using SQL Server 2005 and wish to create a number address records, updating the contact records with the new Id's:
Take the following tables
create table contact(id int primary key identity, home_address_id int, work_address_id int)
create table address(id int primary key identity, street varchar(25), number int)
And foreign keys:
ALTER TABLE dbo.contact ADD CONSTRAINT FK_contact_address1 FOREIGN KEY (home_address_id) REFERENCES dbo.address(id)
ALTER TABLE dbo.contact ADD CONSTRAINT FK_contact_address2 FOREIGN KEY (work_address_id) REFERENCES dbo.address(id)
some dummy data
insert into contact default values
insert into contact default values
insert into contact default values
How can I insert a default empty address record for all contacts who have no home address, and update the home_address_id in one go?
The first part is simple:
insert into address(street) select null from contact where home_address_id is null
I can even get the newly create address id's:
declare #addressTable table(id int)
insert into address(street)
OUTPUT INSERTED.Id INTO #addressTable
select null from contact where home_address_id is null
Here's the new id's
select * from #addressTable
But how to update the contact table with these new Id's?
If possible, I would suggest normalizing your database by adding a Contact_Addresses table:
CREATE TABLE Contact_Addresses
(
contact_id INT NOT NULL,
address_id INT NOT NULL,
address_type VARCHAR(10) NOT NULL,
CONSTRAINT PK_Contact_Addresses PRIMARY KEY CLUSTERED (contact_id, address_id, address_type),
CONSTRAINT FK_ContactAddresses_Contacts (contact_id) REFERENCES Contacts (id),
CONSTRAINT FK_ContactAddresses_Addresses (address_id) REFERENCES Addresses (id),
CONSTRAINT CK_ContactAddresses_address_type CHECK address_type IN ('HOME', 'WORK')
)
Next, I would suggest not putting "dummy" records in your database. It's going to end up causing headaches down the road. The database should contain an accurate record of the data in your system. If you want to display some value by default when no address exists in the system for a contact then handle that in your UI.
If you really must though, then the following code should do the trick:
;WITH C_CTE AS
(
SELECT
id,
home_address_id,
ROW_NUMBER() OVER(ORDER BY id) AS seq
FROM
Contacts
),
(
SELECT
id,
ROW_NUMBER() OVER(ORDER BY id) AS seq
FROM
Addresses
)
UPDATE
C_CTE
SET
home_address_id = A.id
FROM
C_CTE C
INNER JOIN A_CTE A ON A.seq = C.seq
I would do it from the moment you get a new contact, thusly:
[receive contact information]
//prior to inserting contact
declare #homeAddress int, #workAddress int
[insert home address here (real or default based on input)]
set #homeAddress = ##Identity
[insert work address here (real or default)]
set #workAddress = ##Identity
[insert contact here referencing #homeAddress & #workAddress]
For the stuff already in your table, you're going to have to associate all of your null value ids to a contact id. Or, you could clear out your null value addresses, and modify the above statement to an update somehow (brain's not working at the moment, so all I'm coming up with is a cursor, and cursors are evil).