Skip to content

Instantly share code, notes, and snippets.

@digulla
Created October 24, 2014 10:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save digulla/bf1fd374e402db3937f1 to your computer and use it in GitHub Desktop.
Save digulla/bf1fd374e402db3937f1 to your computer and use it in GitHub Desktop.
Groovy tool to count, list or delete orphaned nodes in a database with proper FK relations
import groovy.sql.Sql
class OrphanNodesTool {
Sql sql;
String schema;
Set<String> tablesTargetedByForeignKeys() {
def query = '''\
SELECT referenced_table_name
FROM INFORMATION_SCHEMA.key_column_usage
WHERE referenced_table_schema = ?
'''
def result = new TreeSet()
sql.eachRow( query, [ schema ] ) { row ->
result << row[0]
}
return result
}
String conditionsToFindOrphans( String tableName ) {
List<String> conditions = []
def query = '''\
SELECT referenced_column_name, column_name, table_name
FROM INFORMATION_SCHEMA.key_column_usage
WHERE referenced_table_schema = ?
AND referenced_table_name = ?
'''
sql.eachRow( query, [ schema, tableName ] ) { row ->
conditions << "NOT (${tableName}.${row.referenced_column_name} IN (SELECT ${row.column_name} FROM ${row.table_name}) <=> 1)"
}
return conditions.join( '\nAND ' )
}
List<Long> listOrphanedNodes( String tableName ) {
def query = """\
SELECT ${tableName}.${tableName}_ID
FROM ${tableName}
WHERE ${conditionsToFindOrphans(tableName)}
""".toString()
def result = []
sql.eachRow( query ) { row ->
result << row[0]
}
return result
}
void dumpOrphanedNodes( String tableName ) {
def pks = listOrphanedNodes( tableName )
println( String.format( "%8d %s", pks.size(), tableName ) )
if( pks.size() < 10 ) {
pks.each {
println( String.format( "%16d", it as long ) )
}
} else {
pks.collate( 20 ) { chunk ->
chunk.each {
print( String.format( "%16d ", it as long ) )
}
println()
}
}
}
int countOrphanedNodes( String tableName ) {
def query = """\
SELECT COUNT(*)
FROM ${tableName}
WHERE ${conditionsToFindOrphans(tableName)}
""".toString()
int result;
sql.eachRow( query ) { row ->
result = row[0]
}
return result
}
int deleteOrphanedNodes( String tableName ) {
def query = """\
DELETE
FROM ${tableName}
WHERE ${conditionsToFindOrphans(tableName)}
""".toString()
int result = sql.execute( query )
return result
}
void orphanedNodeStatistics() {
def tableNames = tablesTargetedByForeignKeys()
for( String tableName : tableNames ) {
int n = countOrphanedNodes( tableName )
println( String.format( "%8d %s", n, tableName ) )
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment