2011-09-03 20 views
5

Ho tre tabelle: enter image description here
Per esempio, ecco i dati nel database:

enter image description here
E 'possibile scrivere query che forniscono una griglia come qui di seguito la struttura?

enter image description here
Con interrogazione scritta utilizzando semplici unire il risultato è come qui:

Registrati di query SQL colonne

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

Non capisco cosa stai chiedendo. Potresti riformularlo? –

+0

Off topic: Quello che stai chiedendo è possibile. In primo luogo, viene utilizzato da un'applicazione .NET? Chiedo perché sarebbe molto più pulito eseguire la trasposizione in LINQ –

+0

@Neil Fenwick Sì, è vero. Spiegheresti per favore come faccio a usare LINQ? – Shahin

risposta

2

Grazie per la conferma questo sta per essere consumato da .NET.

La ragione per cui ho chiesto è che non penso che il database sia il posto migliore dove andare su trasformando i dati. Non dicendo che non dovresti mai, solo che è meglio usare il database per quello che è utile: immagazzinare e recuperare i dati e fare la trasformazione nel codice che consuma. È un principio generale per cercare di seguire dove puoi: lascia i tuoi dati in un formato più "grezzo" e quindi più probabile che siano riutilizzabili e consumabili successivamente da altri processi.

In sostanza, ho interpretato il problema è che si desidera:

  1. gruppo per contatto e ContactType,
  2. e poi trasporre & concatenare più righe di numeri di telefono.

io non sono sicuro di quello che il codice .NET che chiama il database assomiglia, ma si poteva fare quanto segue con un DataTable per esempio (ammesso che abbiate qualcosa di simile a 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(); 

Non avevo IDE a disposizione per testare, quindi prendilo come codice approssimativo. Ne ottieni comunque il principio.

+0

+1 questo è il posto giusto per farlo. Vorrei +2 se potessi fornire anche il codice C#. –

+0

Grazie Aaron :) –

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

provare questo codice

1

È possibile utilizzare un CTE per raccogliere i dati mentre si ruotano i numeri di telefono in un elenco separato da virgole. Potrebbe non essere efficiente, ma è un trucco pratico.

I seguenti funzionamenti su AdventureWorks2008R2, anche se avrete bisogno di roba alcuni dati in più nella tabella Person.PersonPhone per creare più numeri di telefono per un singolo tipo di persona/numero.

; 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

Basato sulla risposta di Aaron, prova questa query. Dovrebbe restituire un set di risultati nel modulo che stai cercando.

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