1

この質問が以前に行われたことがある場合は申し訳ありませんが、探しているものがどこにも見つかりません。

セットアップ: 3つのテーブルを持つMSSQLデータベースがあります

テーブル-FoodInfo
-FoodId(PK)、DanName

テーブル-CompName
-CmpId(PK)、CmpName

テーブル-栄養素(ジャンクションテーブル)
-FoodId(FK)、CmpId(fk)、BestLoc

すべてのDanName行には、約8つのCmpNameが関連付けられ、すべてのCmpNameには、1つのBestLocが関連付けられています。

これにより、WinFormでデータを表示すると、DanNameが8回繰り返されます。

問題は、DanNameを関連するCmpNameとその値とともに1行で表示したいということです。

次のようなもの:DanName-CmpName1-BestLoc値-CmpName2-BestLoc値-CmpName3-BestLoc値..など。

私は解決策について非常に柔軟ですが、どの道をたどるべきかわかりません。DBに、希望どおりのテーブルを作成してDataGridViewに配置する必要がありますか、それともLinq-To-SQLを使用して解決し、リストビューに配置する必要がありますか?

すでに述べたように、私はソリューションについてかなり柔軟です。テキストボックスにデータを入れたくないだけです。また、取得したデータをプログラムの他の場所で使用できるようにしたいと思います。

誰かが解決策を持っているなら、私はそれの例を見たいです。

編集: もう少し詳しく説明し、いくつかのコードサンプルを使用します。

linqを使用した私のDALクラス

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    Table<FoodInfo> FoodInfo = db.GetTable<FoodInfo>();
    Table<CompName> CompName = db.GetTable<CompName>();
    Table<Nutrient> Nutrients = db.GetTable<Nutrient>();

    var foods =
        from compname in CompName
        join nutrients in Nutrients on compname.CompId equals nutrients.CompId
        join foodinfo in FoodInfo on nutrients.FoodId equals foodinfo.FoodId
        where foodinfo.DanName.StartsWith(searchWord) && (compname.CompId >= 0
                                                      && compname.CompId < 8)
        select new { foodinfo.DanName, compname.CmpNamDK, nutrients.BestLoc };

    foreach (var food in foods)
    {
        DanName = food.DanName;
        Compname = food.CmpNamDK;
        BestLoc = food.BestLoc;

        OnSearchResultArgs OSR = new OnSearchResultArgs(DanName, Compname, BestLoc);
        onResult(this, OSR);
    }
}

これは私のフォームでイベントハンドラーをトリガーし、結果を送信して次のコードを実行します。

listView1.FullRowSelect = true;
listView1.Columns.Add("DanName", 100);
listView1.Columns.Add("CompName", 150);
listView1.Columns.Add("BestLoc", 50);

private void UpdateControls(object sender, OnSearchResultArgs e)
{
    var item = new ListViewItem();
    item.Text = e.DanName;
    item.SubItems.Add(e.CompName);
    item.SubItems.Add(e.BestLoc);
    listView1.Items.Add(item);
}

UpdateControlが呼び出されていますが、ここに入れる必要はないと思います。

これにより、次のようになります。

それらの8行を1行にしたいと思います。お気に入り:

4

2 に答える 2

0

私には2つの解決策がありますが、どちらにも欠点があります。

最初の解決策はデータを手動でピボットすることですが、8つを超えるCmpNameを開始する場合はクエリを変更する必要があるため、これはあまり動的ではありません。2番目の解決策は、すべてのCmpName値とBestLoc値を1つの列に配置することです。

以下のT-SQLは、両方のソリューションを示す必要があります。

--** Set up test data
DECLARE @FoodInfo Table (FoodId INT, DanName varchar(50));
DECLARE @CompName TABLE (CmpId INT, CmpName VARCHAR(50));
DECLARE @Nutrients TABLE (FoodId INT , CmpId INT, BestLoc VARCHAR(50));

INSERT INTO @FoodInfo (FoodId, DanName)
VALUES  (1, 'Abrikos, torret');

INSERT INTO @CompName (CmpId, CmpName)
VALUES  (1, 'Energi'),(2, 'Protein, total'),(3, 'total-N'),(4, 'Fedt, total'),(5, 'Maettede fedtsyrer'),(6, 'monoumaett, fedtsyrer'),(7, 'polyumaett, fedtsyrer'),(8, 'kulhydrat, tilgaengelig');

INSERT INTO @Nutrients(FoodId, CmpId, BestLoc)
VALUES  (1,1,1159),(1,2,2.9),(1,3,0.5),(1,4,1.7),(1,5,0.1),(1,6,0.6),(1,7,0.6),(1,8,57.2);

--** Standard query
SELECT fi.DanName
     , cn.CmpName
     , n.BestLoc
  FROM @FoodInfo AS fi
  JOIN @Nutrients AS n
    ON fi.FoodId = n.FoodId
  JOIN @CompName AS cn
    ON n.CmpId = cn.CmpId;

--** Manual Pivot
WITH sortCTE AS (
        SELECT fi.DanName
             , cn.CmpName
             , n.BestLoc
             , ROW_NUMBER() OVER (PARTITION BY fi.FoodId ORDER BY cn.CmpId) AS 'col'
          FROM @FoodInfo AS fi
          JOIN @Nutrients AS n
            ON fi.FoodId = n.FoodId
          JOIN @CompName AS cn
            ON n.CmpId = cn.CmpId)
SELECT s.DanName
     , MAX(CASE WHEN s.col = 1 THEN s.CmpName END) AS Cmp1
     , MAX(CASE WHEN s.col = 1 THEN s.BestLoc END) AS BestLoc1
     , MAX(CASE WHEN s.col = 2 THEN s.CmpName END) AS Cmp2
     , MAX(CASE WHEN s.col = 2 THEN s.BestLoc END) AS BestLoc2
     , MAX(CASE WHEN s.col = 3 THEN s.CmpName END) AS Cmp3
     , MAX(CASE WHEN s.col = 3 THEN s.BestLoc END) AS BestLoc3
     , MAX(CASE WHEN s.col = 4 THEN s.CmpName END) AS Cmp4
     , MAX(CASE WHEN s.col = 4 THEN s.BestLoc END) AS BestLoc4
     , MAX(CASE WHEN s.col = 5 THEN s.CmpName END) AS Cmp5
     , MAX(CASE WHEN s.col = 5 THEN s.BestLoc END) AS BestLoc5
     , MAX(CASE WHEN s.col = 6 THEN s.CmpName END) AS Cmp6
     , MAX(CASE WHEN s.col = 6 THEN s.BestLoc END) AS BestLoc6
     , MAX(CASE WHEN s.col = 7 THEN s.CmpName END) AS Cmp7
     , MAX(CASE WHEN s.col = 7 THEN s.BestLoc END) AS BestLoc7
     , MAX(CASE WHEN s.col = 8 THEN s.CmpName END) AS Cmp8
     , MAX(CASE WHEN s.col = 8 THEN s.BestLoc END) AS BestLoc8
  FROM sortCTE AS s
 GROUP BY s.DanName;

--** All in one column
SELECT fi.DanName
     , ISNULL(SUBSTRING((SELECT ', ' + cn.CmpName + ' - ' + CONVERT(VARCHAR(8), n.BestLoc)
                           FROM @Nutrients AS n
                           JOIN @CompName AS cn
                             ON n.CmpId = cn.CmpId
                          WHERE fi.FoodId = n.FoodId
                       ORDER BY cn.CmpId ASC FOR XML PATH('') ), 3, 5000), '') AS 'Cmp'
  FROM @FoodInfo AS fi;

申し訳ありませんが、LINQで同等のクエリがどのように表示されるかはわかりませんが、これにより、目的が何であるかがわかります。

これがお役に立てば幸いです。

于 2013-04-11T20:07:50.630 に答える
0

誰かが私が持っていたのと同じ質問に遭遇した場合の単なる更新。

最初に、T-SQLを使用して@JonPayneのソリューションを試しました。問題は解決しましたが、動作が非常に遅くなりました。マビー私は間違っていた。わからない。

私はここで見つけたガイドからピボットメソッドを作成することになりました:http://www.codeproject.com/Articles/22008/C-Pivot-Table

非常に簡単です。SQL-Serverから順序付けされていないデータをクエリし、それをデータテーブルに入れ、pivotメソッドを使用してデータテーブルをフォーマットします。これにより、順序付けられたデータテーブルが返されます。

于 2013-11-13T11:11:14.697 に答える