2010-01-21 6 views
2

J'ai fait la conception de base de données pour un petit système de CRM. Il comprend des sociétés et des réunions (entre autres).Problème avec mon SQL joindre/groupe par/curseur question

Companies a les champs: ID (primaire, auto_inc) Nom (texte)

Réunions a les champs: ID (primaire, auto_inc) COMPANYID (lien vers Companies.ID) WhenTime (datetime , pour stocker lorsque la réunion a été) notes (texte au sujet de la réunion)

ce que je veux accomplir est une requête qui me donne une liste de toutes les entreprises (tous les champs de la table) et les WhenTime et les notes de la dernière réunion avec cette société (le plus récent est max (WhenTime), et s'il n'y en a pas, NULL va bien).

Je pense que je peux résoudre cela avec des curseurs, mais j'ai peur de la vitesse.

J'ai essayé plusieurs formulations Group By, mais je crains de manquer de finesse.

Ma dernière tentative était la suivante:

select Companies.ID, Companies.name, mts.whentime, mts.notes 
from Companies 
left outer join (
    select top(1) * 
    from Meetings 
    order by [whentime] desc 
) mts 
on Companies.ID = mts.companyID 
order by Companies.name asc 

mais ce code ne prend un tuple de réunions, et non une par entreprise dans la jointure, donc il est pas bon.

Des idées?

+0

Avez-vous besoin d'énumérer toutes les entreprises, ou seulement celles qui ont eu au moins une réunion? –

+0

toutes les entreprises, avec le temps de réunion le plus récent et d'autres choses si disponible – Tominator

Répondre

2

Essayez:

select Companies.ID, Companies.name, mts.whentime, mts.notes 
from Companies 
cross apply 
(
    select top(1) * 
    from Meetings 
    where Companies.ID = Meetings.companyID 
    order by [whentime] desc 
) mts 
order by Companies.name asc; 
+0

Merci! Je ne savais même pas que l'application cross existait ... – Tominator

+0

Si vous voulez inclure des entreprises qui n'ont jamais eu de réunion, utilisez OUTER APPLY au lieu de CROSS APPLY. –

2

Je commencerais en créant une vue des dernières réunions que je trouve la création de vues fait des requêtes complexes plus faciles à lire et à maintenir et peut introduire un élément de réutilisabilité (si bien fait).

CREATE VIEW [dbo].[LatestCompanyNotes] 
AS 

SELECT [CompanyId], [WhenTime], [Notes] 
FROM [Meetings] AS M1 
INNER JOIN 
    (
     SELECT [CompanyId], MAX([Id]) AS [MaxId] 
     FROM [Meetings] 
     GROUP BY [CompanyId] 
    ) AS M2 ON M2.[CompanyId] = M1.[CompanyId] AND M2.[MaxId] = M1.[Id] 

Maintenant, vous devriez être en mesure de se joindre à ce point de vue dans votre requête que vous avez déjà fait.

SELECT Companies.[ID], Companies.[Name], mts.[WhenTime], mts.[Notes] 
FROM [Companies] 
    LEFT OUTER JOIN [dbo].[LatestCompanyNotes] AS mts ON mts.[CompanyId] = Companies.[ID] 
ORDER BY Companies.[Name] ASC 

S'il vous plaît noter que je ne l'ai pas testé le code (je n'ai même pas installé SQL Server) et il peut nécessiter quelques petits changements au travail.

+0

Merci pour votre réponse! Mais je suis allé avec l'autre solution parce que c'est plus petit et ne nécessite pas la vue. – Tominator

+0

Re votre note en bas: Vous étiez * très * proche (impressionnant!).J'ai corrigé le select dans la vue (j'avais besoin d'un alias pour le max (id) et j'ai dû inclure l'identifiant de la compagnie dans la clause 'on'). J'ai testé cette sélection et cela fonctionne. J'ai également fait la jointure dans la sélection finale explicitement externe. –

+0

@Tominator: L'approche de Kane ne nécessite pas * une vue, la vue la simplifie simplement. Il a également l'avantage de ne pas s'appuyer sur une fonctionnalité spécifique à SQL Server (application croisée). –

1

Vous n'avez pas besoin d'une croix-appliquer ici, juste un sous-requête pour trouver la plus récente date de la réunion corrélative:

SELECT Companies.ID, Companies.name, mts.whentime, mts.notes 
FROM Companies 
LEFT OUTER JOIN Meetings mts 
ON Companies.ID = mts.companyID 
AND mts.WhenTime = 
(SELECT MAX(WhenTime) FROM Meetings mtshist WHERE mtshist.companyID = mts.companyID) 
ORDER BY Companies.name 

Notez que ce récupérera toutes les entreprises, y compris celles qui ne l'ont jamais a eu une réunion:

1 Alexander and co. 2010-01-04 some more notes 
2 Barnard Partnership 2010-01-03 NULL 
3 Collingwood Ltd. 2010-01-07 recent meeting 
4 Dimitri and sons NULL  NULL