0

DataTable現在データベースに存在しない日付のレコードのみを残す必要があります。

したがって、ストアド プロシージャを使用して既存のすべての日付を読み取ります (正しいですか?):

SELECT DISTINCT CAST(S.[date] AS DATE) -- original date is DATETIME2(0)
FROM ...
WHERE ...

そしてそれをにロードしますDataTable

var tableDate = new DataTable();
new SqlDataAdapter(command).Fill(tableDate);

別のテーブルから不要な行をすべて削除する方法は? 役立つと思いますLINQが、方法がわかりません..

4

4 に答える 4

2

私はあなたがうまくいくとあなたが言うあなたの答えを見ています、そしてあなたはただ「単一のLINQクエリ」でそれをする方法を知りたいだけです。これらのクエリはすべて実行が延期されているため、次の2つのクエリは機能的に同等であることに注意してください。

var q =
    from d in dates
    select d.Field<DateTime>("date");
return
    (from r in records
     where !q.Contains(r.Field<DateTime>("date"))
     select r).CopyToDataTable();

と:

return
    (from r in records
     where !dates
         .Select(d => d.Field<DateTime>("date"))
         .Contains(r.Field<DateTime>("date"))
     select r).CopyToDataTable();

2番目のバージョンは読みにくいですが、それでも「1つのクエリ」です。


そうは言っても、これらの例はどれも質問のタイトルと実際には一致していないようです。これは、重複する行を削除しようとしていることを示しています。それが本当にあなたがやろうとしていることであるならば、これはそれをする方法です:

static DataTable RemoveDuplicates(DataTable dt)
{
    return
        (from row in dt.Rows.OfType<DataRow>()
         group row by row.Field<string>("date") into g
         select g
            .OrderBy(r => r.Field<int>("ID"))
            .First()).CopyToDataTable();
}

どの重複を削除するかを気にしない場合は、そのOrderBy行を削除するだけです。これは次のようにテストできます。

static void Main(string[] args)
{
    using (DataTable original = CreateSampleTable())
    using (DataTable filtered = RemoveDuplicates(original))
    {
        DumpTable(filtered);
    }
    Console.ReadKey();
}

static DataTable CreateSampleTable()
{
    DataTable dt = new DataTable();
    dt.Columns.Add("ID", typeof(int));
    dt.Columns.Add("Code", typeof(string));
    dt.Columns.Add("Name", typeof(string));
    dt.Rows.Add(1, "123", "Alice");
    dt.Rows.Add(2, "456", "Bob");
    dt.Rows.Add(3, "456", "Chris");
    dt.Rows.Add(4, "789", "Dave");
    dt.Rows.Add(5, "123", "Elen");
    dt.Rows.Add(6, "123", "Frank");
    return dt;
}

static void DumpTable(DataTable dt)
{
    foreach (DataRow row in dt.Rows)
    {
        Console.WriteLine("{0},{1},{2}",
            row.Field<int>("ID"),
            row.Field<string>("Code"),
            row.Field<string>("Name"));
    }
}

RemoveDuplicates(この例のメソッドでは、「date」を「Code」に置き換えるだけです)

うまくいけば、これらの1つがあなたの質問に答えます。そうでなければ、あなたはあなたの要件をより明確にする必要があると思います。

于 2010-02-28T17:49:50.363 に答える
1

あなたが使用することができますExcept()

return records.Except(dates);

更新:入力したフィールドがある 場合DataTableは、次のようになります。

var excluded = arbDates.Rows.OfType<System.Data.DataRow>().Select(a => a[0]) .Except(excDates.Rows.OfType<System.Data.DataRow>().Select(e => e[0]));

それ以外の場合は、次のようにキャストできます。

var excluded = arbDates.Rows.OfType<System.Data.DataRow>() .Select(a => Convert.ToDateTime(a[0].ToString())) .Except( excDates.Rows.OfType<System.Data.DataRow>() .Select(e => Convert.ToDateTime(e[0].ToString())));

于 2010-02-18T18:36:24.073 に答える
1

私が問題を理解しているように、あなたはいくつかのインポートからのデータを重複排除しようとしています。LINQ を使用してこれを行う必要がない場合があります。投稿のタイトルは LINQ を示唆していますが、後で LINQ が最適なソリューションであるかどうか疑問に思うでしょう。私たちが知っていることを考えると、単一の Insert ステートメントを使用してこれを実行できると思います。

まず、次のようにデータをデータベースの一時的な場所に一括コピーすることをお勧めします (まだ行っていない場合)。

Create Table TempBulkCopyData
(
    Id int not null identity(1,1)
    , Date DateTime2 not null
    , ...
)

一時的な場所に一括コピーする利点の 1 つは、インデックスなどを追加してクリーニング プロセスを高速化できることです。データの重複を排除するには、次のようなクエリを実行できます。

Insert DestinationData(...)
Select ...
From BulkCopyData As BCD
Where Id = (
            Select Min(BCD2.[Id])
            From BulkCopyData As BCD2
            Where Cast(BCD2.[Date] As Date) = Cast(BCD.[Date] As Date)
            )

または

Insert DestinationData(...)
Select ...
From BulkCopyData As BCD
Where Id = (
            Select Min(BCD2.[Id])
            From BulkCopyData As BCD2
            Where DateDiff(d, BCD.[Date], BCD2.[Date]) = 0
            )

これにより、最初に見つかった日付 (ID が最も低い日付) が取得されます。これは明らかに恣意的ですが、より洗練させるには、データ構造と要件について詳しく知る必要があります。

于 2010-03-01T19:33:20.983 に答える
1

あなたのSQL文は問題ないようです。私が理解しているように、真夜中から始まるデフォルトの時間値を取得するためにキャストしています。したがって、比較対象の他のテーブルの日付も、日付をニュートラル タイムと比較するためにその形式と一致する必要があります。そうでない場合でも、以下のコードを使用できますが、行のフィールドが参照される.Date場所にプロパティを追加する必要があります。tableResultまた、私は使用Field<DateTime>(0)しましたが、クエリによっては、以前の例に基づいて使用する必要がある場合がありますField<DateTime>("date")

カスタム比較子は必要ありません。LINQ クエリを 1 つのクエリにマージするには、単にletキーワードを使用して、クエリを通じて中間結果を実行し、それを参照することができます。

これを試してください:

var tableDate = new DataTable();
new SqlDataAdapter(command).Fill(tableDate);

// this is the other table that has other dates, so populate as needed
var tableResult = new DataTable();

var newTable =
    (from row in tableResult.AsEnumerable()
    let uniqueRows = tableResult.AsEnumerable().Select(r => r.Field<DateTime>(0))
                                .Except(tableDate.AsEnumerable().Select(r => r.Field<DateTime>(0)))
    where uniqueRows.Contains(row.Field<DateTime>(0))
    select row).CopyToDataTable();

ドット表記では、クエリは次のようになります。

var newTable = tableResult.AsEnumerable()
    .Select(row => new
    {
        Row = row,
        UniqueRows =  tableResult.AsEnumerable()
                                 .Select(r => r.Field<DateTime>(0))
                                 .Except(tableDate.AsEnumerable().Select(r => r.Field<DateTime>(0)))
    })
    .Where(item => item.UniqueRows.Contains(item.Row.Field<DateTime>(0)))
    .Select(item => item.Row)
    .CopyToDataTable();

代わりにortableResult.AsEnumerable()を使用できます。結果は、これらすべてのアプローチで同じです。tableResult.Rows.Cast<DataRow>()tableResult.Rows.OfType<DataRow>()

(新しいテーブルにコピーするのではなく) 既存のテーブルから重複を削除する場合は、Intersect メソッドによって返された項目をテーブルから削除できます。

var commonDates = tableDate.AsEnumerable().Select(row => row.Field<DateTime>(0))
                           .Intersect(tableResult.AsEnumerable().Select(row => row.Field<DateTime>(0)));

for (int index = tableResult.Rows.Count - 1; index >= 0; index--)
{
    if (commonDates.Contains(tableResult.Rows[index].Field<DateTime>(0)))
    {
        tableResult.Rows.RemoveAt(index);
    }
}
于 2010-02-28T18:32:07.527 に答える