2011-09-03 20 views
5

Tengo tres tablas: enter image description here
Por ejemplo, aquí son los datos en la base de datos:

enter image description here
¿Es posible escribir consulta que proporciona una cuadrícula como por debajo de la estructura?

enter image description here
Con consulta por escrito usando sencilla unir el resultado es como aquí:

consulta de combinación columnas de SQL

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

+0

No entiendo lo que está preguntando. ¿Podrías reformularlo? –

+0

Fuera de tema: lo que estás preguntando es posible. En primer lugar, ¿esto es consumido por una aplicación .NET? Lo pregunto porque sería mucho más limpio hacer la transposición en LINQ –

+0

@Neil Fenwick Sí, eso es correcto. ¿Podría explicar por favor cómo hago esto usando LINQ? – Shahin

Respuesta

2

Gracias por confirmar que esto va a ser consumido por NET.

La razón por la que pregunté es porque no creo que la base de datos sea el mejor lugar para hacer transformando los datos. No digo que nunca debas, solo que es mejor usar la base de datos para lo que es bueno: almacenar y recuperar datos, y hacer la transformación en el código de consumo. Es un principio general intentar y seguir donde se pueda: deja sus datos en un formato más "crudo" y, por lo tanto, es más probable que sean reutilizables y consumibles por otros procesos más adelante.

Esencialmente, he interpretado el problema es que desea:

  1. grupo de contacto y ContactType,
  2. y luego transponer & concatenar varias filas de números de teléfono.

no estoy seguro de lo que su código .NET que llama a la base de datos se parece, pero se puede hacer lo siguiente con un DataTable por ejemplo (suponiendo que tiene algo así como un tipo 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(); 

No tenía IDE a mano para probar, así que tome eso como un código aproximado. Sin embargo, obtienes el principio.

+0

+1 este es el lugar correcto para hacerlo. Me gustaría +2 si pudiera proporcionar el código C# también. –

+0

Gracias Aaron :) –

7

Lo que está buscando es la agregación de cadenas. T-SQL no lo hace de forma nativa (otros dbs tienen string_agg, por ejemplo). PERO puedes simularlo.

intente buscar por ejemplo: http://consultingblogs.emc.com/jamiethomson/archive/2009/07/16/string-aggregation-in-t-sql-amp-pl-sql.aspx

o, para los completistas:

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

si busca SQL Server en el último eslabón, hay tres maneras diferentes de hacerlo.

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

probar este código

1

Puede utilizar un CTE para recoger los datos, mientras que la rotación de los números de teléfono en una lista separada por comas. Puede que no sea eficiente, pero es un truco útil.

Los siguientes carreras y AdventureWorks2008R2, aunque tendrá que rellenar algunos datos adicionales en la tabla Person.PersonPhone para crear varios números de teléfono para un solo tipo de persona/número.

; 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 
0

Basado en la respuesta de Aaron, intente esta consulta. Debería devolver un conjunto de resultados en la forma que está buscando.

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 
Cuestiones relacionadas