问题描述
我有一个用 Django 创建的 Postgresql 数据库,里面有很多表。表之间也有多个外键。
我需要更改 users_user 表的 id
(主键)字段,但是有很多表指向它。
当然理想的解决方案是向所有外键添加“ON UPDATE CASCADE”。但在我的情况下,不可能在长时间的协调过程中与其他团队就此类数据库模型更改达成协议。
因此,我需要一种无需手动指定其他表即可自动更改主键和所有外键的方法,因为有很多。
解决方法
零件:
有一种方法可以在没有中间记录的情况下在单个查询中更新主键和外键,此处描述https://stackoverflow.com/a/34383663/2622523
另外,还有一种方法可以知道,哪些表和列通过外键链接到我的表:
SELECT
tc.table_name,kcu.column_name
FROM
information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
AND tc.table_schema = kcu.table_schema
JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
AND ccu.table_schema = tc.table_schema
WHERE tc.constraint_type = 'FOREIGN KEY'
and (tc.table_name='users_user' or ccu.table_name = 'users_user')
所以这两个块可以结合起来生成一个梦的 UPDATE 查询。
解决方案:
这是我遇到的一个查询:
with
-- Source parameters
src as (
select
-- Replace this with your old value,that should be changed
'7f897d30-8261-11eb-8dcd-0242ac130003' as old_value,-- Replace this with your new value,that you need to sed
'f243cc42-1260-4bf0-a452-8ac94b2382df' as new_value,-- Table name,which have to be used
'users_user' as table_name,-- Column that need to be changed
'id' as field_name
),-- here we are memorizing foreign keys,pointing to our table
forkeys as (
SELECT
tc.table_name,kcu.column_name
FROM
information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
AND tc.table_schema = kcu.table_schema
JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
AND ccu.table_schema = tc.table_schema
WHERE tc.constraint_type = 'FOREIGN KEY' and
(
tc.table_name=(select table_name from src)
or
ccu.table_name = (select table_name from src))
),-- constcructing 'with' part of query
withs as (
select e'WITH ' || string_agg(q,e',') as w from (
SELECT
e'\nupdate_' || table_name || '_' || column_name || e' as (\n UPDATE "' || table_name
|| e'" SET "' || column_name || e'" = ''' || (select new_value from src) || ''' where "'
|| column_name || e'" = ''' || (select old_value from src) || e''' returning "'
|| column_name || e'"\n)' as q
FROM
forkeys
) as i
),-- constucting 'main' update part of query
main as (
select 'UPDATE "' || (select table_name from src) || '" SET "' || (select field_name from src) || '" = '''
|| (select new_value from src) || ''' WHERE "' || (select field_name from src) || '" = ''' || (select old_value from src) || '''' as e
)
-- outputting
select w || e'\n' || e from main,withs
在我的例子中这个脚本的输出是:
WITH
update_avatar_useravatar_approver_id as (
UPDATE "avatar_useravatar" SET "approver_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "approver_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "approver_id"
),update_avatar_useravatar_user_id as (
UPDATE "avatar_useravatar" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_awards_useraward_user_id as (
UPDATE "awards_useraward" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_colleagues_colleagues_user_from_id as (
UPDATE "colleagues_colleagues" SET "user_from_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_from_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_from_id"
),update_colleagues_colleagues_user_to_id as (
UPDATE "colleagues_colleagues" SET "user_to_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_to_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_to_id"
),update_congratulations_congratulation_from_user_id as (
UPDATE "congratulations_congratulation" SET "from_user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "from_user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "from_user_id"
),update_congratulations_congratulation_to_user_id as (
UPDATE "congratulations_congratulation" SET "to_user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "to_user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "to_user_id"
),update_django_admin_log_user_id as (
UPDATE "django_admin_log" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_following_userfollowing_from_user_id as (
UPDATE "following_userfollowing" SET "from_user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "from_user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "from_user_id"
),update_following_userfollowing_to_user_id as (
UPDATE "following_userfollowing" SET "to_user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "to_user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "to_user_id"
),update_keycloak_userprofilekeycloak_user_id as (
UPDATE "keycloak_userprofilekeycloak" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_location_table_created_by_id as (
UPDATE "location_table" SET "created_by_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "created_by_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "created_by_id"
),update_profile_media_profileimage_author_id as (
UPDATE "profile_media_profileimage" SET "author_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "author_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "author_id"
),update_skills_skillapproved_user_from_id as (
UPDATE "skills_skillapproved" SET "user_from_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_from_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_from_id"
),update_skills_skillsowners_created_by_id as (
UPDATE "skills_skillsowners" SET "created_by_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "created_by_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "created_by_id"
),update_skills_skillsowners_owner_id as (
UPDATE "skills_skillsowners" SET "owner_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "owner_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "owner_id"
),update_skills_usercompetence_user_id as (
UPDATE "skills_usercompetence" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_structure_unit_boss_id as (
UPDATE "structure_unit" SET "boss_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "boss_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "boss_id"
),update_structure_unit_user_id as (
UPDATE "structure_unit" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_thanks_thanks_from_user_id as (
UPDATE "thanks_thanks" SET "from_user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "from_user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "from_user_id"
),update_thanks_thanks_to_user_id as (
UPDATE "thanks_thanks" SET "to_user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "to_user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "to_user_id"
),update_user_profile_userprofile_call_if_absent_user_id as (
UPDATE "user_profile_userprofile_call_if_absent" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_user_profile_userprofile_mentor_id as (
UPDATE "user_profile_userprofile" SET "mentor_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "mentor_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "mentor_id"
),update_user_profile_userprofile_recruiter_id as (
UPDATE "user_profile_userprofile" SET "recruiter_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "recruiter_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "recruiter_id"
),update_user_profile_userprofile_user_id as (
UPDATE "user_profile_userprofile" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_users_absence_user_id as (
UPDATE "users_absence" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_users_car_user_id as (
UPDATE "users_car" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_users_device_user_id as (
UPDATE "users_device" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_users_education_user_id as (
UPDATE "users_education" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_users_knowlanguage_user_id as (
UPDATE "users_knowlanguage" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_users_user_functional_manager_id as (
UPDATE "users_user" SET "functional_manager_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "functional_manager_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "functional_manager_id"
),update_users_user_groups_user_id as (
UPDATE "users_user_groups" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_users_user_line_manager_id as (
UPDATE "users_user" SET "line_manager_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "line_manager_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "line_manager_id"
),update_users_user_r_functional_manager_id as (
UPDATE "users_user" SET "r_functional_manager_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "r_functional_manager_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "r_functional_manager_id"
),update_users_user_r_line_manager_id as (
UPDATE "users_user" SET "r_line_manager_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "r_line_manager_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "r_line_manager_id"
),update_users_user_user_permissions_user_id as (
UPDATE "users_user_user_permissions" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_users_usersvisibilitysettingsmodel_user_id as (
UPDATE "users_usersvisibilitysettingsmodel" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_location_userplace_user_id as (
UPDATE "location_userplace" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
),update_user_extension_userextension_user_id as (
UPDATE "user_extension_userextension" SET "user_id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' where "user_id" = '7f897d30-8261-11eb-8dcd-0242ac130003' returning "user_id"
)
UPDATE "users_user" SET "id" = 'f243cc42-1260-4bf0-a452-8ac94b2382df' WHERE "id" = '7f897d30-8261-11eb-8dcd-0242ac130003'
可以执行并应用更改。
待办事项:
- 尚不支持复合主键/外键
- 如果您的密钥不是 UUID,没有经过测试,可能会导致一些问题。
- 代码是“只写”需要一些重构
- 也许可以将代码包装到 Pl/PgSQL 代码块中,以便一次性执行。