仅使用一行查询多行结果

时间:2015-09-09 17:11:25

标签: c# sql asp.net sql-server

我正在asp.net开发一个学校项目,我试图得到一个查询,结果有几行(这是相关的),只显示每行“结果”的结果,事情是该项目是一个销售游戏的网页。每个游戏都有几个开发者,类型(动作,FPS等),格式(数字或物理),平台(ps3,ps4等)和其他类似的设置。我测试了它并且它返回了几行,正如我之前所说的那样,它可以被合成为一个具有多个值的行,其中列重复。

以下是查询:

SELECT 
    dbo.Jogos.NomeJogo AS Jogo, 
    dbo.Plataforma.Plataforma,
    dbo.Jogos.disponibilidade, 
    dbo.Jogos.Preco AS Preço, 
    dbo.Jogos.Stock, 
    dbo.Desenvolvedora.NomeDesenvolvedora AS Desenvolvedora, 
    dbo.PEGI.PEGI, 
    dbo.Formato.Formato, 
    dbo.Genero.Genero, 
    dbo.Fornecedor.NomeFornecedor AS Fornecedor 
FROM dbo.Jogos 
    INNER JOIN dbo.Desenvolvedora ON dbo.Jogos.IdDesenvolvedora = dbo.Desenvolvedora.IdDesenvolvedora 
    INNER JOIN dbo.PEGI ON dbo.Jogos.IdPegi = dbo.PEGI.IdPEGI 
    INNER JOIN dbo.GeneroJogo ON dbo.Jogos.IdJogo = dbo.GeneroJogo.IdJogo 
    INNER JOIN dbo.Genero ON dbo.GeneroJogo.IdGenero = dbo.Genero.IdGenero 
    INNER JOIN dbo.JogosFormato ON dbo.Jogos.IdJogo = dbo.JogosFormato.IdJogo 
    INNER JOIN dbo.Formato ON dbo.JogosFormato.IdFormato = dbo.Formato.IdFormato 
    INNER JOIN dbo.JogosFornecedor ON dbo.Jogos.IdJogo = dbo.JogosFornecedor.IdJogo 
    INNER JOIN dbo.Fornecedor ON dbo.JogosFornecedor.IdFornecedor = dbo.Fornecedor.IdFornecedor 
    INNER JOIN dbo.JogosPlataforma ON dbo.Jogos.IdJogo = dbo.JogosPlataforma.IdJogo 
    INNER JOIN dbo.Plataforma ON dbo.JogosPlataforma.IdPlataforma = dbo.Plataforma.IdPlataforma

查询返回同一游戏的几行,可以恢复为只有一行。

例如:

Game              |  Genre   |  Platform  |  Developper
___________________________________________________________

Assassin's Creed  |  Action  |  Ps3       |  Ubisoft
Assassin's Creed  |  Stealth |  Ps3       |  Ubisoft
Assassin's Creed  |  Action  |  xBox 360  |  Ubisoft

我想得到类似的东西:

Game              |  Genre           |  Platform       |  Developper
_____________________________________________________________________

Assassin's Creed  |  Action, Stealth |  Ps3, Xbox 360  |  Ubisoft

我正在寻求帮助,因为我看不出这是怎么可能的。

任何帮助都将不胜感激。

P.S。:查询中的一些值是葡萄牙语。 我也检查了这个帖子 How to use GROUP BY to concatenate strings in SQL Server? 但是这个只使用一个表,我从几个表中获取数据,所以我真的不知道如何继续这个。

提前谢谢你 最好的祝福, 凯文

3 个答案:

答案 0 :(得分:0)

这叫做group_concat in sql server

像:

CREATE TABLE #GAME ([NAME] varchar(50), [Genre] VARCHAR(50), [Platform] varchar(50),Developper VARCHAR(50))

INSERT INTO #GAME  VALUES ('A','g1','ps1','User1'),('A','g2','ps2','User2'),('A','g3','ps1','User1')


SELECT 
  [NAME],
  STUFF((SELECT ', ' + [Genre] FROM #GAME WHERE (NAME = Results.NAME) FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)'),1,2,'') AS GEN1,
  STUFF((SELECT ', ' + [Platform] FROM #GAME WHERE (NAME = Results.NAME) FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)'),1,2,'') AS Platform1,
  STUFF((SELECT ', ' + Developper FROM #GAME WHERE (NAME = Results.NAME) FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)'),1,2,'') AS Developper1

FROM #GAME Results
GROUP BY NAME

编辑2:

CREATE TABLE #GAME ([NAME] varchar(50), [Genre] VARCHAR(50), [Platform] int,Developper VARCHAR(50))
INSERT INTO #GAME  VALUES ('A','g1',1,'User1'),('A','g2',2,'User2'),('A','g3',3,'User1')

Create Table #PLATFORM(ID int,NAME varchar(50),)
INSERT INTO #PLATFORM  VALUES (1,'ps1'),(2,'ps2'),(3,'ps3')


;with cte as
(select gm.Name as Name,pl.Name as plt
from #GAME gm join #PLATFORM pl on gm.Platform=pl.ID
)

select Name,
STUFF((SELECT ', ' + plt FROM cte WHERE (NAME = Results.NAME) FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)'),1,2,'') AS Platform1
FROM cte Results
GROUP BY NAME

答案 1 :(得分:0)

有几种方法可以解决这个问题。 Lanorkin在他/她的评论中引用的问题的接受答案显示其中一个适用于SQL Serer(XML PATH)。如果这听起来有些深奥或可怕,您可以使用相关子查询和用户定义的函数来连接您的值。

基本思想是你有一个外部查询返回游戏的每个唯一值,以及一个内部查询,它可以为类型,平台或开发人员提供连接列表。

create function getPlatforms (@jogoId nvarchar(50))
returns nvarchar(1024)
as 
begin
  declare @platforms nvarchar(1024);
  select @platforms = '';
  -- I understand that your Platform is normalized in your schema, but 
  -- you get the ide. Just make this a join. You can also strip out the 
  -- leading comma one you are done.
  select @platforms = @platforms + ', ' + Plataforma from dbo.Jogos 
        where JogoId = @jogoid;
  return @platforms;
end;
go;


SELECT 
    dbo.Jogos.NomeJogo AS Jogo, 
    dbo.getPlatforms(JogoId)
FROM dbo.Jogos 
GROUP BY NomeJogo, JogoId;

不幸的是,group_concat在SQL Server中不可用(开箱即用),即连接不是聚合操作之一(与SUM,COUNT,AVG等不同)。

各种方法的比较,包括它们的表现,是here

答案 2 :(得分:0)

正如其他人所说,您可以使用xml路径对concat进行分组。但是,从使用大型数据集的个人经验来看,我发现从查询中获取结果然后在代码中将它们连接起来要快得多。

例如,你可以这样创建一个对象:

public class Game
{
    public string Title { get; set; }
    public string Genre { get; set; }
    public string Platform { get; set; }
    public string Developer { get; set; }
}

然后你可以使用linq来操作你认为合适的查询返回的数据集。例如:

using(var command = new SqlCommand())
{
     /*init your sql command */
     var dataSet = new DataSet("Games");
     var dataAdapter = new SqlDataAdapter();
     /*set data adapter command (your query)*/
     dataAdapter.Fill(dataSet);

     var games = new List<Game>();

     var groupings = dataSet.Tables[0].Cast<DataRow>().GroupBy(x => x["Game"].ToString()); //Here we are grouping by games. Based on your example we'll have one group "Assassin's Creed". 

     foreach(var grouping in groupings)
     {
          var firstRow = grouping.First();

          var game = new Game()
          {
               Title = firstRow["Game"].ToString(),
               Genre = string.Join(",", grouping.GroupBy(x => x["Genre"]).Select(x => x.First()["Genre"].ToString()), //Grouping eliminates dupes. This should return Action, Stealth based on your example
               Platform = string.Join(",", grouping.GroupBy(x => x["Platform"]).Select(x => x.First()["Platform"].TosString()),
               Developer = firstRow["Developer"].ToString() //I'm assuming each game has exactly one developer
          }
          games.Add(game);
    }
    //The games list should now have exactly what you need. Based on your example it would have only looped once since there is only one game so you'll have a list with one game object
}

我不确定这是否对您有所帮助,但我发现这比在sql server中通过xml路径进行分组要快得多。