I have a scenario where I query my SQL Server DB, obtain the results, and based on the results, make subsequent queries to the DB again. Following is how I've structured my code for the same:
What I'm interested in knowing is, that is this the correct way to deal with such scenarios?
Should I be doing something else alternatively? Like, make the first call to the DB, load all the results in a dictionary, then make the next calls and use the result stored in the dictionary to make these next calls
(If you feel you need context on what my code does - I want to add a uniqueness constraint and index over columns ColA, ColB, and ColC on MyTable, but I can't directly apply the uniqueness constraint. There are some existing violations over these columns. So I first resolve these violations by changing the value of ColC for the entries that cause the violation, and after fixing all violations, I add the constraint)
void Main() {
using(SqlConnection connection = new SqlConnection(@"Data Source=localhost; Initial Catalog=mydatabase; Integrated Security=True; MultipleActiveResultSets=true"))
{
connection.Open();
//Check if the index exists over Columns ColA_ColB_ColC without the uniqueness constraint
SqlCommand myCommand = new SqlCommand(@"SELECT 1 FROM sys.indexes
WHERE name = 'UQ_ColA_ColB_ColC'
AND object_id = OBJECT_ID('MyTable')
AND is_unique = 0");
SqlDataReader myReader = myCommand.ExecuteReader();
if(myReader.HasRows)
{
try {
//Get the unique values that exist (ColA,ColB,ColC) tuple
myCommand = new SqlCommand(@"select count(*) as count,
ColA,ColB,ColC
from [apimanagement.local].[dbo].[MyTable]
group by ColA,ColB,ColC ", connection);
SqlDataReader myReader = myCommand.ExecuteReader();
while (myReader.Read()) {
//For each of the unique values, get all the rows that have that value
SqlCommand myCommand2 = new SqlCommand(@"select Id,ColA,ColB,ColC from MyTable
where ColA=@ColA and ColB=@ColB and ColC=@ColC", connection);
myCommand2.Parameters.AddWithValue("@ColA", myReader["ColA"].ToString());
myCommand2.Parameters.AddWithValue("@ColB", myReader["ColB"].ToString());
myCommand2.Parameters.AddWithValue("@ColC", myReader["ColC"].ToString());
int index = 2;
SqlDataReader myReader2 = myCommand2.ExecuteReader();
myReader2.Read(); //Read the first row off the results
//If more rows exist, then we have violations for the uniqueness constraint over (ColA,ColB,ColC)
//fix these violations by appending indices to the ColC value
while (myReader2.Read()) {
SqlCommand myCommand3 = new SqlCommand(@"UPDATE MyTable
SET ColC=@NewColC
WHERE Id=@Id", connection);
myCommand3.Parameters.AddWithValue("@Id", myReader2["Id"].ToString());
myCommand3.Parameters.AddWithValue("@NewColC", myReader2["ColC"].ToString()+index);
bool changedSuccessfully = false;
while(!changedSuccessfully)
{
try
{
myCommand3.ExecuteNonQuery();
index++;
break;
}
catch(SqlException e)
{
if((uint)e.HResult == 0x80131904)
{
index++;
}
else
{
throw e;
}
}
}
}
}
//After all the violations are fixed, we create an index over (ColA,ColB,ColC) with the uniqueness constraint
myCommand = new SqlCommand(@"DROP INDEX UQ_ColA_ColB_ColC on [MyTable];
CREATE UNIQUE NONCLUSTERED INDEX [UQ_ColA_ColB_ColC] ON [MyTable]([ColA] ASC, [ColC] ASC, [ColB] ASC) WHERE [ColB] != 3");
myCommand.ExecuteNonQuery();
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
}
}
UPDATEquery that corrects all rows in one go, rather than writing multiple queries and fixing each row individually.