呈现多个sql表

时间:2013-03-24 00:15:37

标签: c# winforms tsql linq-to-sql

很抱歉,如果之前已经问过这个问题,但我无法找到我想要的地方。

设置:我有一个包含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值..等等。

我对解决方案非常灵活,但我不确定要遵循的路径。 我应该尝试在DB中创建一个看起来像我想要的表并将其放在DataGridView中,或者我应该尝试使用Linq-To-SQL解决它并将其放在listview中?

如上所述,我对解决方案非常灵活,我只是不想在文本框中输入数据。 我也希望能够使用我检索的数据并在程序的其他地方使用它。

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

修改 更详细一些,以及一些代码示例。

我的带有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);
    }
}

在我的表单中触发一个eventhandler并发送结果并执行此代码:

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行。像:

2 个答案:

答案 0 :(得分: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中的等效查询会是什么样子,但是这可以让你知道你的目标是什么。

我希望这会有所帮助。

答案 1 :(得分:0)

如果有人遇到与我相同的问题,只需更新。

首先我尝试了@JonPayne的解决方案,使用了T-SQL ..它解决了我的问题,但对我来说工作得很慢。 Maby我做错了。我不知道。

我最终使用我在此处找到的指南制作了一个数据透视方法:http://www.codeproject.com/Articles/22008/C-Pivot-Table

非常简单,我从SQL-Server查询无序数据,将其放入数据表并使用pivot方法格式化数据表,返回有序的数据表。