联接列SQL查询

联接列SQL查询,sql,sql-server,tsql,Sql,Sql Server,Tsql,我有三张桌子: 例如,以下是数据库中的数据: 是否可以编写提供如下结构的网格的查询? 使用简单联接编写查询时,结果如下所示: 在Mysql中,有一个函数组_CONCAT,它将为您执行此操作。AFAIK MSSQL没有类似的功能,但这篇博客文章可能会让您更接近您的目标:您正在寻找的是字符串聚合。T-SQL不是本机实现的,例如,其他数据库都有string_agg。但你可以模拟它 请尝试查找,例如: 或者,对于完成者: 如果在最后一个链接中搜索SQL Server,有三种不同的方法 select s

我有三张桌子: 例如,以下是数据库中的数据: 是否可以编写提供如下结构的网格的查询? 使用简单联接编写查询时,结果如下所示:


在Mysql中,有一个函数组_CONCAT,它将为您执行此操作。AFAIK MSSQL没有类似的功能,但这篇博客文章可能会让您更接近您的目标:

您正在寻找的是字符串聚合。T-SQL不是本机实现的,例如,其他数据库都有string_agg。但你可以模拟它

请尝试查找,例如:

或者,对于完成者:

如果在最后一个链接中搜索SQL Server,有三种不同的方法

select stuff((select distinct ','+ numbers from testtable for xml path('')),1,1,'')

请尝试此代码

谢谢您确认.NET将使用此代码

我问的原因是,我认为数据库不是转换数据的最佳场所。并不是说您永远不应该这样做,而是说最好使用数据库来实现它擅长的功能:存储和检索数据,并在消费代码中进行转换。这是一个可以尝试并遵循的一般原则—它以更原始的格式保留数据,因此以后更可能被其他流程重用和使用

本质上,我认为问题在于你想:

按联系人和联系人类型分组, 然后转置并连接多行电话号码。 我不确定调用数据库的.NET代码是什么样子的,但您可以使用DataTable执行以下操作,例如,假设您有联系人类型:


我手头没有IDE来测试,所以把它当作粗略的代码。不过,您可以从中获得原理。

您可以使用CTE收集数据,同时将电话号码旋转到逗号分隔的列表中。它可能效率不高,但却是一个方便的技巧

以下内容在AdventureWorks2008R2上运行,不过您需要在Person.PersonPhone表中填充一些额外数据,以便为单个Person/number类型创建多个电话号码

; 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

根据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

我不明白你在问什么。你能重新措辞吗?离题:你所问的是可能的。首先,这是由.NET应用程序使用的吗?我这样问是因为这样做会更干净LINQ@Neil芬威克是的,没错。你能解释一下我是如何使用LINQ来做这件事的吗?可能是+1的副本这是正确的地方。如果我能提供C代码,我会+2。
; 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
    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