1

I have Added many columns in a Table in a SQL database.

Now when I tried a code to DROP columns from this Table, I received an error that I must first DROP the constraints for the actual column that I try to DROP.

So my question is how I can return ALL constraint names for the columns in the:
Table: DateTimes (in the Database: DatabaseTest).

I have googled this but have not found a straight forward code example of how to do this.
The line I could find was:
"show table status from " + databaseName + " where name = '" + datatableName + "';";

The code below doesn't work but I wonder if it is possible to complete this code to return the constraint names for all columns in the table DateTimes?

Thank you!

    void showContstraintsForTable()
    {
        String databaseName = "DatabaseTest";
        String datatableName = "DateTimes";


        using (SqlConnection conn = new SqlConnection(GetConnectionString()))
        {
            conn.Open();
            String cmdString = "show table status from " + databaseName + " where name = '" + datatableName + "';";
            using (SqlCommand comm = new SqlCommand(cmdString))
            {
                try
                {
                    comm.Connection = conn;

                    //How to return all CONSTRAINTS for all columns in this table?

                }
                catch (SqlException ex) { MessageBox.Show(ex.ToString()); }
            }
        }
    }
    static private string GetConnectionString()
    {
        return "Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename=C:\\Users\\andre\\source\\repos\\TestDatabaseCreation\\DatabaseTest.mdf;Integrated Security=True;Connect Timeout=30";
    }
coding
  • 53
  • 1
  • 9
  • What is your database ? There is no standard for retrieve constraints' names, it is done differently on each database. – krokodilko Oct 04 '20 at 11:06
  • Yes that was what confused me from all google searches: My database is `SQL` and the name of the database is `DatabaseTest` – coding Oct 04 '20 at 11:07

1 Answers1

0

The following gets foreign key constraints where one method gets all tables at once and the second one table only.

Hopefully if this is not an exact solution you it can provide another idea to work with via some code or sql modifications.

Original SQL came from this post

I used a Windows form app for visuals but does not need a user interface.

Container for constraint information

public class Constraints
{
    public string TableName { get; set; }
    public string ConstraintName { get; set; }
    public string ColumnName { get; set; }
    public string ReferencedTable { get; set; }
    public string ReferencedColumn { get; set; }
    public override string ToString() => TableName;
}

SQL Statements

    public class QueryStatements
    {
        /// <summary>
        /// Get all tables with foreign keys
        /// </summary>
        /// <returns></returns>
        public static string ForeignKeysAllTables() =>
            @"
SELECT 
TableName = t.Name,constr.name AS ConstraintName, cols.name AS ColumnName, t2.name AS ReferencedTable, c2.name AS ReferencedColumn
FROM sys.tables t
     INNER JOIN sys.foreign_keys constr ON constr.parent_object_id = t.object_id
     INNER JOIN sys.tables t2 ON t2.object_id = constr.referenced_object_id
     INNER JOIN sys.foreign_key_columns fkc ON fkc.constraint_object_id = constr.object_id
     INNER JOIN sys.columns cols ON cols.object_id = fkc.parent_object_id AND cols.column_id = fkc.parent_column_id
     INNER JOIN sys.columns c2 ON c2.object_id = fkc.referenced_object_id AND c2.column_id = fkc.referenced_column_id
ORDER BY t.Name, cols.name;

";

        /// <summary>
        /// Get foreign keys for a single table
        /// </summary>
        /// <returns></returns>
        public static string ForeignKeysForSingleTable() =>
            @"
SELECT 
TableName = t.Name,constr.name AS ConstraintName, cols.name AS ColumnName, t2.name AS ReferencedTable, c2.name AS ReferencedColumn
FROM sys.tables t
     INNER JOIN sys.foreign_keys constr ON constr.parent_object_id = t.object_id
     INNER JOIN sys.tables t2 ON t2.object_id = constr.referenced_object_id
     INNER JOIN sys.foreign_key_columns fkc ON fkc.constraint_object_id = constr.object_id
     INNER JOIN sys.columns cols ON cols.object_id = fkc.parent_object_id AND cols.column_id = fkc.parent_column_id
     INNER JOIN sys.columns c2 ON c2.object_id = fkc.referenced_object_id AND c2.column_id = fkc.referenced_column_id 
WHERE t.name = @TableName
ORDER BY t.Name, cols.name;

";
        /// <summary>
        /// Get all table names in a database
        /// </summary>
        /// <param name="databaseName"></param>
        /// <returns></returns>
        public static string GetTableNames(string databaseName) =>
            $"SELECT TABLE_NAME FROM [{databaseName}].INFORMATION_SCHEMA.TABLES " + 
            "WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME <> 'sysdiagrams' ORDER BY TABLE_NAME";
    }

Data class

public class Informational
{
    /// <summary>
    /// For a real app the connection string could come
    /// from app.config, adjust as needed
    /// </summary>
    private static string _databaseName = "NorthWind2020";

    private static string _connectionString = 
        "Data Source=.\\SQLEXPRESS;" +
        $"Initial Catalog={_databaseName};" +
        "Integrated Security=True";

    public static List<Constraints> GetAllTablesForeignConstraints() 
    {
        var results = new List<Constraints>();

        using (var cn = new SqlConnection {ConnectionString = _connectionString})
        {

            using (var cmd = new SqlCommand {Connection = cn})
            {
                cmd.CommandText = QueryStatements.ForeignKeysAllTables();
                cn.Open();

                var reader = cmd.ExecuteReader();

                while (reader.Read())
                {
                    results.Add(new Constraints()
                    {
                        TableName = reader.GetString(0),
                        ConstraintName = reader.GetString(1),
                        ColumnName = reader.GetString(2),
                        ReferencedTable = reader.GetString(3),
                        ReferencedColumn = reader.GetString(4)
                    });
                }
            }
        }

        return results;

    }
    public static List<Constraints> GetTableForeignConstraints(string tableName)
    {
        var results = new List<Constraints>();

        using (var cn = new SqlConnection { ConnectionString = _connectionString })
        {

            using (var cmd = new SqlCommand { Connection = cn })
            {
                cmd.CommandText = QueryStatements.ForeignKeysForSingleTable();
                cmd.Parameters.AddWithValue("@TableName", tableName);

                cn.Open();

                var reader = cmd.ExecuteReader();

                while (reader.Read())
                {
                    results.Add(new Constraints()
                    {
                        TableName = reader.GetString(0),
                        ConstraintName = reader.GetString(1),
                        ColumnName = reader.GetString(2),
                        ReferencedTable = reader.GetString(3),
                        ReferencedColumn = reader.GetString(4)
                    });
                }
            }
        }

        return results;

    }

    public static List<string> GetTableNameList()
    {
        var results = new List<string>();

        using (var cn = new SqlConnection {ConnectionString = _connectionString})
        {
            using (var cmd = new SqlCommand {Connection = cn})
            {
                cmd.CommandText = QueryStatements.GetTableNames(_databaseName);
                cn.Open();

                var reader = cmd.ExecuteReader();

                while (reader.Read())
                {
                    results.Add(reader.GetString(0));
                }
            }
        }

        return results;
    }
}

In a form, a ListBox is loaded with table names (does not mean they have constraints) and a TextBox to display information. On selection change of the ListBox with table names constraints are retrieved or a hard coded sample for one table via Button Click event.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SqlServerUtilities;

namespace SqlServerUtilitiesFrontEnd
{
    public partial class Form1 : Form
    {
        private List<Constraints> _constraints;
        public Form1()
        {
            InitializeComponent();

            Shown += Form1_Shown;
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            _constraints = Informational.GetAllTablesForeignConstraints();

            TableNameListBox.DataSource = Informational.GetTableNameList();
            DisplayForeignConstraintNames();

            TableNameListBox.SelectedIndexChanged += TableNameListBox_SelectedIndexChanged;
        }

        private void TableNameListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            DisplayForeignConstraintNames();
        }

        private void DisplayForeignConstraintNames()
        {
            var constraints = _constraints
                .Where(item => item.TableName == TableNameListBox.Text).ToList();

            var sb = new StringBuilder();

            foreach (var constraint in constraints)
            {
                sb.AppendLine($"{constraint.ConstraintName}, {constraint.ReferencedColumn}");
            }

            ResultsTextBox.Text = sb.Length == 0 ? "None" : sb.ToString();
            
        }

        private void GetCustomersForeignConstraintsButton_Click(object sender, EventArgs e)
        {

            var constraints = Informational.GetTableForeignConstraints("Customers");
            var sb = new StringBuilder();

            foreach (var constraint in constraints)
            {
                sb.AppendLine($"{constraint.ConstraintName}, {constraint.ReferencedColumn}");
            }

            ResultsTextBox.Text = sb.Length == 0 ? "None" : sb.ToString();
        }
    }
}

I placed all classes in a class project as the Windows Form project is for demo purposes while the class project contains what is needed.

enter image description here

enter image description here

Karen Payne
  • 4,341
  • 2
  • 14
  • 31