我有三张桌子:
例如,这里是数据库的数据:
是否可以编写提供类似以下结构的网格的查询?
使用简单连接编写查询时,结果如下:
SELECT dbo.Contact.ContactID, dbo.Contact.ContactName, dbo.PhoneNumber.PhoneNO, dbo.PhoneType.TypeTitle
FROM dbo.Contact INNER JOIN
dbo.PhoneNumber ON dbo.Contact.ContactID = dbo.PhoneNumber.ContactID AND dbo.Contact.ContactID = dbo.PhoneNumber.ContactID INNER JOIN
dbo.PhoneType ON dbo.PhoneNumber.PhoneType = dbo.PhoneType.PhoneTypeI
答案 0 :(得分:7)
您正在寻找的是字符串聚合。 T-SQL原生不这样做(其他dbs例如有string_agg)。但你可以模拟它。
或者,对于completists:
http://www.postgresonline.com/journal/archives/191-stringagg.html
如果您在上一个链接中搜索SQL Server
,则有三种不同的方法。
答案 1 :(得分:2)
感谢您确认这将由.NET使用。
我问的原因是我不认为数据库是转换数据的最佳位置。不是说你永远不应该,只是最好使用数据库来擅长:存储和检索数据,并在消费代码中进行转换。它的一般原则是尽可能地尝试和遵循 - 它使您的数据保持更“原始”的格式,因此以后更有可能被其他流程重复使用和消费。
基本上,我解释的问题是你想:
我不确定您调用数据库的.NET代码是什么样的,但是您可以使用DataTable
执行以下操作(假设您有类似Contact
类型的内容):
List<Contact> results = (
from dataRow in myDataTable.AsEnumerable()
let contactData = new {
ContactName = dataRow.Field<string>("ContactName"),
PhoneType = dataRow.Field<string>("PhoneType"),
PhoneNumber = dataRow.Field<string>("PhoneNO")
}
group contactData by new { contactData.ContactName, contactData.PhoneType } into grp
select new Contact {
ContactName = grp.Key.ContactName,
PhoneType = grp.Key.PhoneType,
PhoneNumber = grp.Aggregate( (cumulativeText, contact) => String.Format("{0}, {1}", cumulativeText, contact.PhoneNumber) )
}
).ToList();
我没有IDE可以用来测试,所以把它作为粗略的代码。你从中得到了原则。
答案 2 :(得分:1)
select stuff((select distinct ','+ numbers from testtable for xml path('')),1,1,'')
试试此代码
答案 3 :(得分:1)
您可以使用CTE收集数据,同时将电话号码转换为逗号分隔列表。它可能效率不高,但这是一个方便的技巧。
以下在AdventureWorks2008R2上运行,但您需要在Person.PersonPhone表中填充一些额外数据,以便为单个人/数字类型创建多个电话号码。
; with PersonsWithTelephoneNumbersCTE (
BusinessEntityId, FirstName, MiddleName, LastName,
PhoneNumberTypeId, PhoneNumber, PhoneNumbers, Elements )
as (
-- Base case: Just the person identifications with all possible phone types.
select BusinessEntityID, FirstName, MiddleName, LastName, PhoneNumberTypeId,
cast( '' as NVarChar(25) ), cast( '' as VarChar(MAX) ), 0
from Person.Person as PP cross join
Person.PhoneNumberType as PNT
union all
-- Add a telephone number.
select CTE.BusinessEntityId, CTE.FirstName, CTE.MiddleName, CTE.LastName,
PNT.PhoneNumberTypeID, PN.PhoneNumber,
cast( CTE.PhoneNumbers + ', ' + PN.PhoneNumber as VarChar(MAX) ), CTE.Elements + 1
from PersonsWithTelephoneNumbersCTE as CTE inner join
Person.Person as PP on PP.BusinessEntityID = CTE.BusinessEntityId inner join
Person.PhoneNumberType as PNT on PNT.PhoneNumberTypeID = CTE.PhoneNumberTypeId inner join
Person.PersonPhone as PN on PN.BusinessEntityID = CTE.BusinessEntityId and PN.PhoneNumberTypeID = PNT.PhoneNumberTypeID
where PN.PhoneNumber > CTE.PhoneNumber
)
-- Get the person and the longest list of phone numbers for each person/phone type.
select LastName, FirstName, MiddleName,
(select Name from Person.PhoneNumberType where PhoneNumberTypeID = Edna.PhoneNumberTypeID ) as PhoneNumberType,
substring( PhoneNumbers, 3, len( PhoneNumbers ) - 2 ) as PhoneNumbers from (
select BusinessEntityID, FirstName, MiddleName, LastName, PhoneNumberTypeId, PhoneNumbers,
rank() over ( partition by BusinessEntityId, PhoneNumberTypeId order by Elements desc ) as Ranking
from PersonsWithTelephoneNumbersCTE
) as Edna
where Ranking = 1 and PhoneNumbers <> ''
order by LastName, FirstName, MiddleName, PhoneNumberType
答案 4 :(得分:0)
在Mysql中,有一个函数GROUP_CONCAT
可以为你做这个。 AFAIK MSSQL没有相应的功能,但是这篇博文可能会让您更接近目标:http://explainextended.com/2010/06/21/group_concat-in-sql-server/
答案 5 :(得分:0)
基于Aaron的答案,尝试这个查询。它应该以您正在寻找的形式返回结果集。
SELECT DISTINCT
c.ContactName
,pt.TypeTitle
,(SELECT pn2.PhoneNO + ', '
FROM dbo.PhoneNumber AS pn2
WHERE pn.PhoneType = pn2.PhoneType
AND pn.ContactID = pn2.ContactID
FOR XML PATH ('')
) AS Numbers
FROM dbo.Contact AS c
INNER JOIN dbo.PhoneNumber AS pn
ON c.ContactID = pn.ContactID
INNER JOIN dbo.PhoneType AS pt
ON pn.PhoneType = pt.PhoneTypeID