1

抱歉,如果以前有人问过这个问题,但我在任何地方都找不到我要找的东西。

设置:我有一个带有 3 个表的 MS SQL 数据库

- FoodInfo
- FoodId(PK)、DanName

- CompName
- CmpId(PK)、CmpName

- 营养素(连接表)
- FoodId(FK)、CmpId(fk)、BestLoc

对于每个 DanName 行,关联大约 8 个 CmpName,对于每个 CmpName,关联 1 个 BestLoc

当我在我的 winform 中显示数据时,这导致 DanName 重复 8 次。

问题是,我想在一行中显示 DanName 以及相关的 CmpName 及其值。

类似于:DanName - CmpName1 - BestLoc 值 - CmpName2 - BestLoc 值 - CmpName3 - BestLoc 值..等等。

我对解决方案非常灵活,但我不确定要遵循什么路径。我应该尝试在数据库中创建一个看起来像我想要的表并将其放入 DataGridView 中,还是应该尝试使用 Linq-To-SQL 解决它并将其放入列表视图中?

如前所述,我对解决方案非常灵活,我只是不希望文本框中的数据。我还希望可以使用我检索到的数据并在我的程序的其他地方使用它。

如果有人有解决方案,我很乐意看到一个例子。

编辑: 更详细一点,并带有一些代码示例。

我的 DAL 类与 linq

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

我有两个解决方案,都有各自的缺点。

第一个解决方案是手动旋转数据,但这不是很动态,因为如果您开始拥有超过 8 个 CmpName,则必须更改查询,而第二个解决方案是将所有 CmpName 和 BestLoc 值放在一个列中。

下面的 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 查询我的无序数据,将其放入数据表中并使用数据透视方法格式化数据表,该方法返回有序数据表。

于 2013-11-13T11:11:14.697 回答