-2

c# を使用した (My)Sql の日付の違いについて質問があります。
私のデータベースには、次のような日付範囲を含むテーブルがあります。

------------------------
日付から日付まで
-------------------------
2012-07-01 2012-07-03
2012-07-05 2012-07-07
2012-07-10 2012-07-12
2012-07-13 2012-07-16
--------------------------

これらの範囲から、含まれるすべての日付を結果として計算したい、つまり:

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

SELECT DATEDIFF('2012-01-01', '2012-02-02')期待どおりに機能しません。合計日数しか表示されません...範囲の日付(FromDateとToDate)を含む、この間のすべての日付が必要です。

これを (SQL または C# で) 実装する方法を教えてもらえますか?

4

3 に答える 3

1

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 が返されます)。fromDatetoDate

    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 つのメモ:

LinqToEntityLinqToSQLは、データベースへの「ブリッジ」です。

これらはオブジェクト リレーショナル マッパーであり、(指定したデータベース接続を介して) 適切なデータベース ドライバーを使用して 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 年間の日付を計算する場合に必要になります。

于 2012-07-05T08:56:21.597 に答える
0

私があなたを正しく理解しているなら、あなたは以下を含むテーブルを持っています:

------------------------
From date      to date
-------------------------
2012-07-01    2012-07-03
2012-07-05    2012-07-07
2012-07-10    2012-07-12
2012-07-13    2012-07-16
--------------------------

そして、それに対してSQLを実行し、リストされているすべての「開始日」と「終了日」の間のすべての日付を取得します。

単純に(つまり、あまり深く考えずに)、MySqlはそれを行いません-テーブルから既存のレコードを返します。すでにac#アプリケーションを使用しているので、MySqlからレコードを読み取り、関連するすべての日付の独自のリストを作成する方が簡単なようです(ただし、これは、それらをどのように処理するかによって異なります)。

于 2012-07-05T07:40:09.017 に答える
0

おかげさまでC#で修正しました。mysqlで何も見つかりません。

dtDetailsは、DBからの値(fromdateおよびto date)を含むデータテーブルです。

次に、もう1つのデータテーブルを作成し、(fromdate --todate)からのすべての値を保存しました

次に、そのデータテーブルを使用します。

if(dtDetails.Rows.Count> 0)

{ foreach (DataRow dr in dtDetails.Rows) { DateTime startingDate = Convert.ToDateTime( dr["fromdate"]); DateTime endingDate = Convert.ToDateTime(dr["todate"]); DateTime newdate; for (newdate = startingDate; newdate <= endingDate; newdate = newdate.AddDays(1)) { DataRow dr2 = dt2.NewRow(); dt2.Rows.Add(newdate); } } }
于 2012-07-05T10:05:30.300 に答える