2011-10-11 7 views
2

Je pensais à une vue/requête complexe que je devais créer, mais je n'arrive pas à trouver une bonne solution (ou une solution de travail) à mon problème. D'abord, je vais vous donner un morceau de ma structure de base de données pour expliquer mon problème:Vue compliquée de SQL Server 2008 R2

sql server diagram

Chaque accord a généralement 3 personnes impliquées: un client, un endclient et un ContactPerson. Ces types de rôle sont définis dans la table PersonAgreementInvolvementRole. Ce que je veux est de créer une vue où je peux obtenir les trois noms de personnes impliquées dans l'accord, donc quelque chose comme ceci:

AgreementID | ClientName | EndClientName | ContactPersonName 

      1 | Company1 |  Company2 |  Smith 

Parce que je dois aller à la même table (personne) à chaque fois pour obtenir le nom de la personne impliquée, je ne sais pas comment je peux le faire le mieux. J'ai d'abord essayé quelque chose comme ceci:

select ag.StartDate, ag.EndDate, ag.PriceRate, ag.TaskDescription, pc.Name as ClientName, pec.Name as EndClientName 
from dbo.Agreement ag inner join dbo.PersonAgreementInvolvement pai 
on ag.AgreementID = pai.AgreementID 
inner join dbo.Person pc 
on pai.PersonID = pc.PersonID 
inner join dbo.PersonAgreementInvolvementRole pairc 
on pai.PersonAgreementInvolvementRoleID = pairc.PersonAgreementInvolvementRoleID 
inner join dbo.Person pec 
on pai.PersonID = pec.PersonID 
inner join dbo.PersonAgreementInvolvementRole pairec 
on pai.PersonAgreementInvolvementRoleID = pairec.PersonAgreementInvolvementRoleID 
where pairec.Value = 'Client' 
and 
pairc.Value = 'EndClient' 

mais cela ne fonctionne pas (il est revenu aucune donnée), après que j'ai essayé une requête avec un syndicat mais aussi n'a pas fonctionné.

L'un de vous a une idée? Plus d'informations peuvent être fournies si nécessaire, il suffit de demander!

données Exemple:

J'ai un accord (AgreementID = 1) avec deux personnes impliquées. Il y a une personne avec le nom "Google" qui a l'InvolvementRole "Client" et une autre personne nommée "Microsoft" qui a l'InvolvementRole "EndClient". Ce que je voudrais obtenir de ma requête est la suivante:

AgreementID - Client - EndClient 
-------------------- ----------------- 
1    Google  Microsoft 

EDIT: RESOLU! En fin de compte, cette requête a fait le travail:

SELECT ag.StartDate, ag.EndDate, ag.PriceRate, CAST(ag.TaskDescription AS VARCHAR(8000)), 
     MIN(CASE WHEN pair.Value = 'Klant' THEN pc.Name END) as Klant, 
     MIN(CASE WHEN pair.Value = 'Eindklant' THEN pc.Name END) as Eindklant, 
     MIN(CASE WHEN pair.Value = 'ContactPerson' THEN pc.Name END) as ContactPersonName 
FROM dbo.Agreement ag 
INNER JOIN dbo.PersonAgreementInvolvement pai 
ON ag.AgreementID = pai.AgreementID 
inner join dbo.PersonAgreementInvolvementRole pair 
on pai.PersonAgreementInvolvementRoleID = pair.PersonAgreementInvolvementRoleID 
LEFT JOIN dbo.Person pc 
ON pai.PersonID = pc.PersonID 
GROUP BY ag.StartDate, ag.EndDate, ag.PriceRate, CAST(ag.TaskDescription AS VARCHAR(8000)) 

Merci à tous ceux qui m'ont aidé à le résoudre! :)

+2

"SQL Server Complicated" devrait être une alternative à "SQL Server Compact" :) Merci – MatBailie

Répondre

1

Si je comprends bien la structure correctement, cela devrait faire l'affaire:

QUERY MISE À JOUR

WITH PersonsInvolved AS 
(
    SELECT AgreementID, 
      MIN(CASE WHEN pai.Value = 'Client' THEN pc.Name END) as ClientName, 
      MIN(CASE WHEN pai.Value = 'EndClient' THEN pc.Name END) as EndClientName, 
      MIN(CASE WHEN pai.Value = 'ContactPerson' THEN pc.Name END) as ContactPersonName 
    FROM dbo.PersonAgreementInvolvement pai 
    LEFT JOIN dbo.Person pc 
    ON pai.PersonID = pc.PersonID 
    GROUP BY AgreementID 
) 
SELECT ag.StartDate, ag.EndDate, ag.PriceRate, ag.TaskDescription, 
     pin.ClientName, pin.EndClientName, pin.ContactPersonName 
FROM dbo.Agreement ag 
INNER JOIN PersonsInvolved pin 
ON ag.AgreementID = pin.AgreementID 
+0

Je reçois l'erreur suivante "Les types de données text, ntext et image ne peuvent pas être comparés ou triés, sauf en cas d'utilisation de l'opérateur IS NULL ou LIKE." sur la ligne de l'instruction GROUP BY. Je suis désolé, je n'ai pas créé de groupe par requêtes depuis 2 ans :) –

+0

@JelleCapenberghs - Alors, laquelle de vos colonnes est du type 'text'? – Lamak

+0

TaskDescription est du type Texte. Si je le supprime du groupe par l'instruction, il est dit "Colonne 'dbo.Agreement.TaskDescription' n'est pas valide dans la liste de sélection, car il ne figure ni dans une fonction d'agrégat ni dans la clause GROUP BY.". Mais si j'enlève la description de la tâche, cela fonctionne comme je le veux! Mais je voudrais aussi inclure la description de la tâche –

1

Le code inclus dans la question devrait travail, bien que je serais enclin à changer le joint à gauche jointures externes (et déplacer les conditions where à se joindre à des conditions, faute de quoi ils se tourneront efficacement en arrière jointures externes aux jointures internes).

est ici une approche différente:

select ag.AgreementID, 
     max(ag.StartDate), 
     max(ag.EndDate), 
     max(ag.PriceRate), 
     max(ag.TaskDescription), 
     max(case parl.value when 'Client' then psn.name else '' end), 
     max(case parl.value when 'EndClient' then psn.name else '' end), 
     max(case parl.value when 'ContactPerson' then psn.name else '' end) 
from dbo.Agreement ag 
left join dbo.PersonAgreementInvolvement pai  on ag.AgreementID = pai.AgreementID 
left join dbo.Person psn       on pai.PersonID = pc.PersonID 
left join dbo.PersonAgreementInvolvementRole parl on pai.PersonAgreementInvolvementRoleID = parl.PersonAgreementInvolvementRoleID 
group by ag.AgreementID 

Autre possibilité:

select ag.AgreementID, 
     ag.StartDate, 
     ag.EndDate, 
     ag.PriceRate, 
     ag.TaskDescription, 
     parl.value as role, 
     psn.name 
from dbo.Agreement ag 
left join dbo.PersonAgreementInvolvement pai  on ag.AgreementID = pai.AgreementID 
left join dbo.Person psn       on pai.PersonID = pc.PersonID 
left join dbo.PersonAgreementInvolvementRole parl on pai.PersonAgreementInvolvementRoleID = parl.PersonAgreementInvolvementRoleID 

- doivent montrer tous les rôles qui sont effectivement sélectionnés par accord (mais pas sur la même ligne).

+0

Marque! Votre première requête donne toujours une erreur mais votre deuxième requête fonctionne. Je suppose que je peux utiliser une expression lambda dans mon programme actuel pour obtenir la bonne valeur selon un rôle d'un accord. Ce n'est toujours pas le point de vue que j'aimerais avoir, mais je peux continuer à travailler sur mon programme avec votre solution.Merci beaucoup! –

+0

Quelle est l'erreur pour la première requête? Le seul problème possible que je peux voir est que les champs dans la clause SELECT n'ont pas de noms alias à eux. – MatBailie

+0

Il est dit "Le texte du type de données d'opérande est invalide pour l'opérateur max." à la ligne de la max (ag.StartDescription) et quand je supprime le max il est dit "Colonne 'dbo.Agreement.TaskDescription' est invalide dans la liste de sélection car il n'est pas contenu dans une fonction d'agrégat ou la clause GROUP BY. " La TaskDescription est du type de données Texte –