我正在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? 但是这个只使用一个表,我从几个表中获取数据,所以我真的不知道如何继续这个。
提前谢谢你 最好的祝福, 凯文
答案 0 :(得分:0)
像:
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路径进行分组要快得多。