加入列SQL查询

时间:2011-09-03 08:04:27

标签: sql sql-server tsql

我有三张桌子: enter image description here
例如,这里是数据库的数据:

enter image description here
是否可以编写提供类似以下结构的网格的查询?

enter image description here
使用简单连接编写查询时,结果如下:

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

enter image description here

6 个答案:

答案 0 :(得分:7)

您正在寻找的是字符串聚合。 T-SQL原生不这样做(其他dbs例如有string_agg)。但你可以模拟它。

尝试查找示例: http://consultingblogs.emc.com/jamiethomson/archive/2009/07/16/string-aggregation-in-t-sql-amp-pl-sql.aspx

或者,对于completists:

http://www.postgresonline.com/journal/archives/191-stringagg.html

如果您在上一个链接中搜索SQL Server,则有三种不同的方法。

答案 1 :(得分:2)

感谢您确认这将由.NET使用。

我问的原因是我不认为数据库是转换数据的最佳位置。不是说你永远不应该,只是最好使用数据库来擅长:存储和检索数据,并在消费代码中进行转换。它的一般原则是尽可能地尝试和遵循 - 它使您的数据保持更“原始”的格式,因此以后更有可能被其他流程重复使用和消费。

基本上,我解释的问题是你想:

  1. 按联系人和ContactType分组
  2. 然后转置&连接多行电话号码
  3. 我不确定您调用数据库的.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