Skip to content

Commit 75bbce3

Browse files
JaBistDuNarrischJaBistDuNarrisch
authored andcommitted
UpdateFromTableToTable for SQLite, Postgre, Oracle and SQL Server
1 parent a3f63b6 commit 75bbce3

File tree

8 files changed

+227
-0
lines changed

8 files changed

+227
-0
lines changed

src/Migrator/Framework/ITransformationProvider.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Data;
4+
using DotNetProjects.Migrator.Framework.Models;
45

56
namespace DotNetProjects.Migrator.Framework;
67

@@ -645,6 +646,15 @@ IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string
645646

646647
int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues);
647648

649+
/// <summary>
650+
/// Updates the target table using data from the source table updating the target table. Make sure to only use primary keys or unique columns in <paramref name="conditionColumnPairs"/>
651+
/// </summary>
652+
/// <param name="tableSourceNotQuoted"></param>
653+
/// <param name="tableTargetNotQuoted"></param>
654+
/// <param name="fromSourceToTargetColumnPairs">Pairs that represent the name of the source column and the column in the target table to be updated.</param>
655+
/// <param name="conditionColumnPairs">Pairs that represent the name of the source column and the name of the target tabel used to match the rows.</param>
656+
void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs);
657+
648658
/// <summary>
649659
/// Get a command instance
650660
/// </summary>

src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using DotNetProjects.Migrator.Framework;
2+
using DotNetProjects.Migrator.Framework.Models;
23
using DotNetProjects.Migrator.Providers.Impl.Oracle.Models;
34
using DotNetProjects.Migrator.Providers.Models;
45
using DotNetProjects.Migrator.Providers.Models.Indexes;
@@ -907,6 +908,52 @@ public override bool IndexExists(string table, string name)
907908
return Convert.ToInt32(scalar) == 1;
908909
}
909910

911+
public override void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs)
912+
{
913+
if (!TableExists(tableSourceNotQuoted))
914+
{
915+
throw new Exception($"Table '{tableSourceNotQuoted}' given in '{nameof(tableSourceNotQuoted)}' does not exist");
916+
}
917+
918+
if (!TableExists(tableTargetNotQuoted))
919+
{
920+
throw new Exception($"Table '{tableTargetNotQuoted}' given in '{nameof(tableTargetNotQuoted)}' does not exist");
921+
}
922+
923+
if (fromSourceToTargetColumnPairs.Length == 0)
924+
{
925+
throw new Exception($"{nameof(fromSourceToTargetColumnPairs)} is empty.");
926+
}
927+
928+
if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted)))
929+
{
930+
throw new Exception($"One of the strings in {nameof(fromSourceToTargetColumnPairs)} is null or empty");
931+
}
932+
933+
if (conditionColumnPairs.Length == 0)
934+
{
935+
throw new Exception($"{nameof(conditionColumnPairs)} is empty.");
936+
}
937+
938+
if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted)))
939+
{
940+
throw new Exception($"One of the strings in {nameof(conditionColumnPairs)} is null or empty");
941+
}
942+
943+
var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted);
944+
var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted);
945+
946+
var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}").ToList();
947+
948+
var conditionStrings = conditionColumnPairs.Select(x => $"t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}");
949+
950+
var assignStringsJoined = string.Join(", ", assignStrings);
951+
var conditionStringsJoined = string.Join(" AND ", conditionStrings);
952+
953+
var sql = $"MERGE INTO {tableNameTarget} t ON ({conditionStringsJoined}) WHEN MATCHED THEN UPDATE SET {assignStringsJoined}";
954+
ExecuteNonQuery(sql);
955+
}
956+
910957
private string SchemaInfoTableName
911958
{
912959
get

src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#endregion
1313

1414
using DotNetProjects.Migrator.Framework;
15+
using DotNetProjects.Migrator.Framework.Models;
1516
using DotNetProjects.Migrator.Providers.Models.Indexes;
1617
using DotNetProjects.Migrator.Providers.Models.Indexes.Enums;
1718
using System;
@@ -815,6 +816,52 @@ public override bool IndexExists(string table, string name)
815816
return reader.Read();
816817
}
817818

819+
public override void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs)
820+
{
821+
if (!TableExists(tableSourceNotQuoted))
822+
{
823+
throw new Exception($"Table '{tableSourceNotQuoted}' given in '{nameof(tableSourceNotQuoted)}' does not exist");
824+
}
825+
826+
if (!TableExists(tableTargetNotQuoted))
827+
{
828+
throw new Exception($"Table '{tableTargetNotQuoted}' given in '{nameof(tableTargetNotQuoted)}' does not exist");
829+
}
830+
831+
if (fromSourceToTargetColumnPairs.Length == 0)
832+
{
833+
throw new Exception($"{nameof(fromSourceToTargetColumnPairs)} is empty.");
834+
}
835+
836+
if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted)))
837+
{
838+
throw new Exception($"One of the strings in {nameof(fromSourceToTargetColumnPairs)} is null or empty");
839+
}
840+
841+
if (conditionColumnPairs.Length == 0)
842+
{
843+
throw new Exception($"{nameof(conditionColumnPairs)} is empty.");
844+
}
845+
846+
if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted)))
847+
{
848+
throw new Exception($"One of the strings in {nameof(conditionColumnPairs)} is null or empty");
849+
}
850+
851+
var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted);
852+
var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted);
853+
854+
var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}").ToList();
855+
856+
var conditionStrings = conditionColumnPairs.Select(x => $"t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}");
857+
858+
var assignStringsJoined = string.Join(", ", assignStrings);
859+
var conditionStringsJoined = string.Join(" AND ", conditionStrings);
860+
861+
var sql = $"MERGE INTO {tableNameTarget} t ON ({conditionStringsJoined}) WHEN MATCHED THEN UPDATE SET {assignStringsJoined}";
862+
ExecuteNonQuery(sql);
863+
}
864+
818865
protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value)
819866
{
820867
if (value is ushort)

src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using DotNetProjects.Migrator.Framework.Extensions;
1313
using DotNetProjects.Migrator.Providers.Models.Indexes;
1414
using DotNetProjects.Migrator.Providers.Models.Indexes.Enums;
15+
using DotNetProjects.Migrator.Framework.Models;
1516

1617
namespace DotNetProjects.Migrator.Providers.Impl.SQLite;
1718

@@ -209,6 +210,52 @@ public override ForeignKeyConstraint[] GetForeignKeyConstraints(string tableName
209210
return foreignKeyConstraints.ToArray();
210211
}
211212

213+
public override void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs)
214+
{
215+
if (!TableExists(tableSourceNotQuoted))
216+
{
217+
throw new Exception($"Table '{tableSourceNotQuoted}' given in '{nameof(tableSourceNotQuoted)}' does not exist");
218+
}
219+
220+
if (!TableExists(tableTargetNotQuoted))
221+
{
222+
throw new Exception($"Table '{tableTargetNotQuoted}' given in '{nameof(tableTargetNotQuoted)}' does not exist");
223+
}
224+
225+
if (fromSourceToTargetColumnPairs.Length == 0)
226+
{
227+
throw new Exception($"{nameof(fromSourceToTargetColumnPairs)} is empty.");
228+
}
229+
230+
if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted)))
231+
{
232+
throw new Exception($"One of the strings in {nameof(fromSourceToTargetColumnPairs)} is null or empty");
233+
}
234+
235+
if (conditionColumnPairs.Length == 0)
236+
{
237+
throw new Exception($"{nameof(conditionColumnPairs)} is empty.");
238+
}
239+
240+
if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted)))
241+
{
242+
throw new Exception($"One of the strings in {nameof(conditionColumnPairs)} is null or empty");
243+
}
244+
245+
var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted);
246+
var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted);
247+
248+
var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = {tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}").ToList();
249+
250+
var conditionStrings = conditionColumnPairs.Select(x => $"{tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = {tableNameTarget}.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}");
251+
252+
var assignStringsJoined = string.Join(", ", assignStrings);
253+
var conditionStringsJoined = string.Join(" AND ", conditionStrings);
254+
255+
var sql = $"UPDATE {tableNameTarget} SET {assignStringsJoined} FROM {tableNameSource} WHERE {conditionStringsJoined}";
256+
ExecuteNonQuery(sql);
257+
}
258+
212259
private List<PragmaForeignKeyListItem> GetForeignKeyListItems(string tableNameNotQuoted)
213260
{
214261
List<PragmaForeignKeyListItem> pragmaForeignKeyListItems = [];

src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#endregion
1313

1414
using DotNetProjects.Migrator.Framework;
15+
using DotNetProjects.Migrator.Framework.Models;
1516
using DotNetProjects.Migrator.Providers.Models.Indexes;
1617
using System;
1718
using System.Collections.Generic;
@@ -800,6 +801,52 @@ public override void RenameTable(string oldName, string newName)
800801
ExecuteNonQuery(string.Format("EXEC sp_rename '{0}', '{1}'", oldName, newName));
801802
}
802803

804+
public override void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs)
805+
{
806+
if (!TableExists(tableSourceNotQuoted))
807+
{
808+
throw new Exception($"Table '{tableSourceNotQuoted}' given in '{nameof(tableSourceNotQuoted)}' does not exist");
809+
}
810+
811+
if (!TableExists(tableTargetNotQuoted))
812+
{
813+
throw new Exception($"Table '{tableTargetNotQuoted}' given in '{nameof(tableTargetNotQuoted)}' does not exist");
814+
}
815+
816+
if (fromSourceToTargetColumnPairs.Length == 0)
817+
{
818+
throw new Exception($"{nameof(fromSourceToTargetColumnPairs)} is empty.");
819+
}
820+
821+
if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted)))
822+
{
823+
throw new Exception($"One of the strings in {nameof(fromSourceToTargetColumnPairs)} is null or empty");
824+
}
825+
826+
if (conditionColumnPairs.Length == 0)
827+
{
828+
throw new Exception($"{nameof(conditionColumnPairs)} is empty.");
829+
}
830+
831+
if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted)))
832+
{
833+
throw new Exception($"One of the strings in {nameof(conditionColumnPairs)} is null or empty");
834+
}
835+
836+
var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted);
837+
var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted);
838+
839+
var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}").ToList();
840+
841+
var conditionStrings = conditionColumnPairs.Select(x => $"t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}");
842+
843+
var assignStringsJoined = string.Join(", ", assignStrings);
844+
var conditionStringsJoined = string.Join(" AND ", conditionStrings);
845+
846+
var sql = $"MERGE INTO {tableNameTarget} t ON ({conditionStringsJoined}) WHEN MATCHED THEN UPDATE SET {assignStringsJoined}";
847+
ExecuteNonQuery(sql);
848+
}
849+
803850
// Deletes all constraints linked to a column. Sql Server
804851
// doesn't seems to do this.
805852
private void DeleteColumnConstraints(string table, string column)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace DotNetProjects.Migrator.Framework.Models;
2+
3+
/// <summary>
4+
/// Represents a column pair for usage e.g. in a column comparison.
5+
/// </summary>
6+
public class ColumnPair
7+
{
8+
/// <summary>
9+
/// Gets or sets the column name of the source table. Use the not quoted column name.
10+
/// </summary>
11+
public string ColumnNameSourceNotQuoted { get; set; }
12+
13+
/// <summary>
14+
/// Gets or sets the column name of the target table. Use the not quoted column name.
15+
/// </summary>
16+
public string ColumnNameTargetNotQuoted { get; set; }
17+
}

src/Migrator/Providers/NoOpTransformationProvider.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Data;
44
using DotNetProjects.Migrator.Framework;
5+
using DotNetProjects.Migrator.Framework.Models;
56
using DotNetProjects.Migrator.Framework.SchemaBuilder;
67
using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint;
78
using Index = DotNetProjects.Migrator.Framework.Index;
@@ -591,4 +592,9 @@ public void AddColumn(string table, string column, MigratorDbType type, object d
591592
{
592593
throw new NotImplementedException();
593594
}
595+
596+
public void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs)
597+
{
598+
throw new NotImplementedException();
599+
}
594600
}

src/Migrator/Providers/TransformationProvider.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
using DotNetProjects.Migrator.Framework;
1515
using DotNetProjects.Migrator.Framework.Loggers;
16+
using DotNetProjects.Migrator.Framework.Models;
1617
using DotNetProjects.Migrator.Framework.SchemaBuilder;
1718
using DotNetProjects.Migrator.Providers.Impl.SQLite;
1819
using DotNetProjects.Migrator.Providers.Models;
@@ -1331,6 +1332,11 @@ public virtual int Update(string table, string[] columns, object[] values, strin
13311332
return command.ExecuteNonQuery();
13321333
}
13331334

1335+
public virtual void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs)
1336+
{
1337+
throw new NotImplementedException();
1338+
}
1339+
13341340
public virtual int Insert(string table, string[] columns, object[] values)
13351341
{
13361342
if (string.IsNullOrEmpty(table))

0 commit comments

Comments
 (0)