1 つ目は LINQ を使用する C# で、2 つ目は再帰 CTE 手法を使用して日付を生成する SQL です。あなたがより好きなものを自由に選んでください。
I. LINQ を使用したソリューション:
C# を使用しているとのことですが、この場合は LINQ を利用でき、ソリューションは次のプログラムです (LinqPad または VisualStudio で実行できるコンソール アプリケーションの例)。
private static void Main(string[] args)
{
var query1 = from r in RangeTable.AsQueryable() select r;
query1.Dump("List of ranges:");
Console.WriteLine();
query1.CreateDates().Dump("Result list of dates:");
Console.ReadLine();
}
RangeTable
範囲テーブルをクエリ可能なオブジェクト リストとして返すプロパティです (例: LinqToEntityまたはLinqToSQLを使用)。
興味深い部分は拡張メソッド CreateDates
です:
public static IQueryable<DateTime> CreateDates(this IQueryable<DateRange> rtbl)
{
var result = new List<DateTime>();
foreach (var dr in rtbl)
{
var q = from i in Enumerable.Range(0, dr.CalcDays())
select (DateTime)dr.fromDate.AddDays(i);
foreach (var d in q) result.Add(d);
}
return result.AsQueryable<DateTime>();
}
この関数は、とCalcDays
の間の日数を計算する単純な拡張メソッドを使用しています(fromDate と toDate が等しい場合、意図的に 1 が返されます)。fromDate
toDate
public static int CalcDays(this DateRange dr)
{
var days = (int)(dr.toDate - dr.fromDate).TotalDays + 1;
return days;
}
RangeTable
次に、機能に関するいくつかの詳細。DateRange
日付範囲の 2 つのプロパティを実装するクラスが必要です。
public class DateRange
{
public DateTime fromDate;
public DateTime toDate;
}
この例RangeTable
では、簡単にするためにデータベース接続なしで定義されていますが、LinqToSQL または LinqToEntity も使用できます。
private static List<DateRange> RangeTable
{
get
{
var result = new List<DateRange>() {
new DateRange() { fromDate = new DateTime(2012, 07, 01), toDate = new DateTime(2012, 07, 03) },
new DateRange() { fromDate = new DateTime(2012, 07, 05), toDate = new DateTime(2012, 07, 07) },
new DateRange() { fromDate = new DateTime(2012, 07, 10), toDate = new DateTime(2012, 07, 12) },
new DateRange() { fromDate = new DateTime(2012, 07, 13), toDate = new DateTime(2012, 07, 16) }
};
return result;
}
}
最後に、LinqPadがなく、代わりに VisualStudio で例を使用したい場合は、次のように 2 つの Dump 拡張メソッドを簡単に定義できます。
const string dateMask = "yyyy-MM-dd";
public static void Dump(this IQueryable<DateRange> item, string msg)
{
Console.WriteLine(msg);
foreach (var i in item)
{
Console.WriteLine(string.Format("{0} to {1}", i.fromDate.ToString(dateMask), i.toDate.ToString(dateMask)));
}
}
public static void Dump(this IQueryable<DateTime> item, string msg)
{
Console.WriteLine(msg);
foreach (var i in item)
{
Console.WriteLine(string.Format("{0}", i.ToString(dateMask)));
}
}
public static class Extensions
他の拡張メソッドと一緒に
最上位に配置するだけです。注:クラスDateRange
は最上位クラスであり、メソッドRangeTable
は内部Program
クラス内で定義されます。
このサンプルでは、次の出力が生成されます。
List of ranges:
2012-07-01 to 2012-07-03
2012-07-05 to 2012-07-07
2012-07-10 to 2012-07-12
2012-07-13 to 2012-07-16
Result list of dates:
2012-07-01
2012-07-02
2012-07-03
2012-07-05
2012-07-06
2012-07-07
2012-07-10
2012-07-11
2012-07-12
2012-07-13
2012-07-14
2012-07-15
2012-07-16
最後に 1 つのメモ:
LinqToEntityとLinqToSQLは、データベースへの「ブリッジ」です。
これらはオブジェクト リレーショナル マッパーであり、(指定したデータベース接続を介して) 適切なデータベース ドライバーを使用して LINQ ステートメントを SQL に変換し、SQL クエリを "ジャスト イン タイム" に送信し、データベースに関する実装固有の詳細を隠します。標準化された LINQ クエリのプログラミングに集中できます。
この例では、プロパティ RangeTable を変更して、mySQL データベースにクエリを実行し、IQueryable オブジェクトを返すようにする必要があります。必要なのは次のとおりです。
- LinqPad に新しい接続を追加するには、必要なテーブルまでドリルダウンし、最後にクエリにドラッグ アンド ドロップします (または、名前が既に一致している場合は、接続を追加して [接続] をクリックします)。
LinqToEntities を使用するには:新しいアイテムをプロジェクトに追加し、「データ」で「ADO.NET エンティティ データ モデル」を選択し、「データベースから生成」を選択し、目的のデータベース接続を追加し、テーブルを追加します。Model1.edmxファイルが生成されます。たとえば、これをNortwindでテストした場合、サンプル クエリは次のようになります。
var entities = new NorthwindEntities1();
entities.Connection.Open();
var query1 = from c in entities.Customers select c;
Ⅱ.SQL を使用したソリューション:
これを解決するために、T-SQL 2008 で利用可能な共通テーブル式 (別名 CTE) を使用することもできます。
with
sampleTable as (
select CAST('2012-07-05' as DATETIME) fromDt
,CAST('2012-07-08' as DATETIME) toDt
union
select CAST('2012-08-01' as DATETIME) fromDt
,CAST('2012-08-11' as DATETIME) toDt
),
calcdiff as (
select DATEDIFF(day, fromDt, toDt) d
,*
from sampleTable
),
recursion as (
select fromDt as dt, toDt from calcdiff
union all
select dateadd(day, 1, dt) dt2, toDt from recursion
where dateadd(day, 1, dt)<=toDt
)
select dt as Result from recursion
order by dt
SampleTable
「実際の」SQL テーブルに置き換えることができます。これは、この例を完全にするために使用されcalcdiff
、日付の違いをrecursion
計算し、必要なすべての日付を再帰的に計算します: 結合の最初の部分は、必須の再帰のアンカーです。CTE 再帰では が必要であることに注意してくださいunion all
。それ以外の場合、T-SQL はクエリを実行しません。
再帰レベルが原因でエラーが発生した場合は、追加するだけです
option (maxrecursion 365);
これにより、「より深い」再帰が可能になります。たとえば、1 年間の日付を計算する場合に必要になります。