按依赖顺序排序的MySQL表名

时间:2017-06-27 15:46:41

标签: mysql foreign-keys database-schema

我想通过它的依赖顺序来获取表名。

例如:如果我有表格usersusers_ordersorders我希望获得此订单的表名:users(或orders不问题),ordersusers_orders

如果有办法请帮助。

2 个答案:

答案 0 :(得分:3)

听起来您正在尝试转储具有外键定义的表,并且您希望确保首先转储“父”表,以便可以确保引用它们的“子”表的外键定义将是工作

通常不能这样做,因为循环依赖是可能的。

例如,如果您有usersteams,其中每个用户都有对其所属团队的引用,但teams也有一个引用captain作为团队队长的特定用户,您要首先列出users还是先列出teams

一种替代解决方案是以您想要的任何顺序输出所有表,但没有外键定义。在列出所有表及其数据之后,然后使用ALTER TABLE...ADD FOREIGN KEY命令进行操作。

另一个替代解决方案 - mysqldump使用的解决方案 - 在开头是SET FOREIGN_KEY_CHECKS=0。然后,您可以定义外键约束,而无需担心引用的表是否已创建。这些表按字母顺序转储。

但是要更直接地回答您的问题:您可以使用INFORMATION_SCHEMA来发现存在哪些表依赖项。

SELECT table_schema, table_name, 
  GROUP_CONCAT(column_name ORDER BY ordinal_position) AS `columns`,
  MAX(referenced_table_schema) AS referenced_table_schema,
  MAX(referenced_table_name) AS referenced_table_name,
  GROUP_CONCAT(referenced_column_name ORDER BY ordinal_position) AS `ref_columns`
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE referenced_table_schema IS NOT NULL
GROUP BY table_schema, table_name;

在MySQL 8.0(仍在开发中)之前,MySQL不支持递归查询。因此,您可能必须将依赖项数据提取到应用程序中,并找出要转储它们的顺序。

但你仍然无法以这种方式处理周期。你必须使用我上面描述的替代方案之一。

答案 1 :(得分:0)

您可以这样做。

1)获取所有不具有外键依赖性的表的列表。

SELECT table_name FROM information_schema.tables WHERE table_schema='my_database' AND table_name NOT IN (SELECT distinct table_name FROM information_schema.key_column_usage WHERE table_schema='my_database' AND referenced_table_name IS NOT NULL;

2)获取具有外键依赖关系的表的列表,该表与另一个没有任何前键依赖关系的表有关。

SELECT DISTINCT table_name FROM information_schema.referential_constraints WHERE constraint_schema='my_database' AND referenced_table_name NOT IN (SELECT DISTINCT table_name FROM information_schema.table_constraints WHERE constraint_type = 'FOREIGN KEY') AND table_name NOT IN (SELECT DISTINCT table_name FROM information_schema.referential_constraints WHERE referenced_table_name IN (SELECT DISTINCT table_name FROM information_schema.table_constraints WHERE constraint_type = 'FOREIGN KEY'));

3)获取具有外键依赖关系的表的清单,以及其他本身具有外键依赖关系的表的清单。

SELECT DISTINCT table_name FROM information_schema.referential_constraints WHERE constraint_schema='my_database' AND referenced_table_name IN (SELECT DISTINCT table_name FROM information_schema.table_constraints WHERE constraint_type = 'FOREIGN KEY');

然后,您可以在下面的脚本中使用它们。它不会解决上述循环依赖问题,但会创建一个MySQL转储文件,其中表按外键依赖关系排序。

#!/usr/bin/env bash
#
# staged-mysqldump.sh
#
# Runs mysqldump against a database and splits the output into
# three directories.
#
# <database_name>-STAGE-1 contains dumps of all of the tables
# that don't have any foreign key constraints.
# <database_name>-STAGE-2 contains dumps of all of the tables
# that have only have foreign key constraints with other tables
# that don't have foreign key constraints.
# <database_name>-STAGE-3 contains dumps of the rest of the tables.
#
#
DATABASE="$1"
DUMPDIR="/var/tmp"
MYSQL_CREDENTIALS="~/.my.cnf"
DUMPDATE="$(date +%Y%m%d)"
#
# Write a statement that drops the database if it exists and
# then write a create database statement to simulate a regular
# mysqldump.
#
echo "DROP DATABASE IF EXISTS $DATABASE;" >> $DUMPDIR/$DATABASE-$DUMPDATE-dump.sql
mysql --defaults-extra-file=$MYSQL_CREDENTIALS --skip-column-names --batch --execute "SHOW CREATE DATABASE $DATABASE" | sed "s/^$DATABASE\s\+//;s/$/;/" >> $DUMPDIR/$DATABASE-$DUMPDATE-dump.sql
#
# Dump the stage 1 tables.
#
printf "Dumping tables for %s - Stage 1\n" "$DATABASE"
STAGE_1_TABLES=$(mysql --defaults-extra-file=$MYSQL_CREDENTIALS --skip-column-names --batch --execute "SELECT table_name FROM information_schema.tables WHERE table_schema='$DATABASE' AND table_name NOT IN (SELECT distinct table_name FROM information_schema.key_column_usage WHERE table_schema='$DATABASE' AND referenced_table_name IS NOT NULL)")
printf "Stage 1 Start Time: %(%Y-%m-%d - %H:%M:%S)T\n"
mysqldump --defaults-extra-file=$MYSQL_CREDENTIALS --databases $DATABASE --tables $STAGE_1_TABLES >> $DUMPDIR/$DATABASE-$DUMPDATE-dump.sql
printf "Finished dumping tables for %s - Stage 1\n" "$DATABASE"
printf "Stage 1 End Time: %(%Y-%m-%d - %H:%M:%S)T\n"
#
# Dump the stage 2 tables.
#
printf "Dumping tables for %s - Stage 2\n" "$DATABASE"
STAGE_2_TABLES=$(mysql --defaults-extra-file=$MYSQL_CREDENTIALS --skip-column-names --batch --execute "SELECT DISTINCT table_name FROM information_schema.referential_constraints WHERE constraint_schema='$DATABASE' AND referenced_table_name NOT IN (SELECT DISTINCT table_name FROM information_schema.table_constraints WHERE constraint_type = 'FOREIGN KEY') AND table_name NOT IN (SELECT DISTINCT table_name FROM information_schema.referential_constraints WHERE referenced_table_name IN (SELECT DISTINCT table_name FROM information_schema.table_constraints WHERE constraint_type = 'FOREIGN KEY'))")
printf "Stage 2 Start Time: %(%Y-%m-%d - %H:%M:%S)T\n"
mysqldump --defaults-extra-file=$MYSQL_CREDENTIALS --databases $DATABASE --tables $STAGE_2_TABLES >> $DUMPDIR/$DATABASE-$DUMPDATE-dump.sql
printf "Finished dumping tables for %s - Stage 2\n" "$DATABASE"
printf "Stage 2 End Time: %(%Y-%m-%d - %H:%M:%S)T\n"
#
# Dump the stage 3 tables.
#
printf "Dumping tables for %s - Stage 3\n" "$DATABASE"
STAGE_3_TABLES=$(mysql --defaults-extra-file=$MYSQL_CREDENTIALS --skip-column-names --batch --execute "SELECT DISTINCT table_name FROM information_schema.referential_constraints WHERE constraint_schema='$DATABASE' AND referenced_table_name IN (SELECT DISTINCT table_name FROM information_schema.table_constraints WHERE constraint_type = 'FOREIGN KEY')")
printf "Stage 3 Start Time: %(%Y-%m-%d - %H:%M:%S)T\n"
mysqldump --defaults-extra-file=$MYSQL_CREDENTIALS --databases $DATABASE --tables $STAGE_2_TABLES >> $DUMPDIR/$DATABASE-$DUMPDATE-dump.sql
printf "Finished dumping tables for %s - Stage 3\n" "$DATABASE"
printf "Stage 3 End Time: %(%Y-%m-%d - %H:%M:%S)T\n"

如果使用此选项,您可能需要调整传递给MySQL的选项。