2010-08-24 6 views
3

J'ai une table:sélectionnez dans SQL Server 2005

ID | first | end 
-------------------- 
a |  1 | 3 
b |  3 | 8 
c |  8 | 10 

Je veux sélectionner suivante:

ID | first | end 
--------------------- 
a-c |  1 | 10 

Mais je ne peux pas le faire. S'il vous plaît! Aidez moi. Merci!

Répondre

1

Cela fonctionne pour moi:

SELECT MIN(t.id)+'-'+MAX(t.id) AS ID, 
     MIN(t.[first]) AS first, 
     MAX(t.[end]) AS [end] 
    FROM dbo.YOUR_TABLE t 

Mais s'il vous plaît, ne pas utiliser des mots réservés comme "fin" pour les noms de colonnes.

+0

Je vois. Mais il i ont un suivi de la table: ID première extrémité un 1 3 3 8 b c 8 10 d 15 19 e 10 12 f 19 23 je pense que ce faux. Parce que je veux sélectionner ID première extrémité un-e 3 12 d-f 15 23 –

+0

@Vuong: Je pense, cependant, vous pouvez étendre cette idée pour répondre à vos besoins. Si vous ajoutez une colonne calculée à votre sélection pour générer vos en-têtes de regroupement (pensez à utiliser une instruction 'case' pour calculer la colonne), puis groupez sur le calcul, vous pouvez toujours appliquer' MIN' et 'MAX' comme suggéré ici. – kbrimington

+0

@Voung Mao: C'est un ensemble de données différent de ce que vous avez posté dans votre question - si c'est ce que vous traitez, vous devriez poster la question avec ce détail parce que quelqu'un doit lire votre commentaire pour connaître d'autres critères. On ne sait pas non plus comment vous savez qu'il y a deux groupes dans cet ensemble de données, ou où ils commencent et se terminent. –

0

Je crois que vous pouvez le faire en utilisant un recursive Common Table Expression comme suit, surtout si vous n'êtes pas attendre de très longues chaînes de disques:

WITH Ancestors AS 
(
    SELECT 
     InitRow.[ID] AS [Ancestor], 
     InitRow.[ID], 
     InitRow.[first], 
     InitRow.[end], 
     0 AS [level], 
     '00000' + InitRow.[ID] AS [hacky_level_plus_ID] 
    FROM 
     YOUR_TABLE AS InitRow 
    WHERE 
     NOT EXISTS 
     (
      SELECT * FROM YOUR_TABLE AS PrevRow 
      WHERE PrevRow.[end] = InitRow.[first] 
     ) 
    UNION ALL 
    SELECT 
     ParentRow.Ancestor, 
     ChildRow.[ID], 
     ChildRow.[first], 
     ChildRow.[end], 
     ParentRow.level + 1 AS [level], 
     -- Avoids having to build the recursive structure more than once. 
     -- We know we will not be over 5 digits since CTEs have a recursion 
     -- limit of 32767. 
     RIGHT('00000' + CAST(ParentRow.level + 1 AS varchar(4)), 5) 
      + ChildRow.[ID] AS [hacky_level_plus_ID] 
    FROM 
     Ancestors AS ParentRow 
     INNER JOIN YOUR_TABLE AS ChildRow 
      ON ChildRow.[first] = ParentRow.[end] 
) 
SELECT 
    Ancestors.Ancestor + '-' + SUBSTRING(MAX([hacky_level_plus_ID]),6,10) AS [IDs], 
-- Without the [hacky_level_plus_ID] column, you need to do it this way: 
-- Ancestors.Ancestor + '-' + 
--  (SELECT TOP 1 Children.ID FROM Ancestors AS Children 
--  WHERE Children.[Ancestor] = Ancestors.[Ancestor] 
--  ORDER BY Children.[level] DESC) AS [IDs], 
    MIN(Ancestors.[first]) AS [first], 
    MAX(Ancestors.[end]) AS [end] 
FROM 
    Ancestors 
GROUP BY 
    Ancestors.Ancestor 
-- If needed, add OPTION (MAXRECURSION 32767) 

Une explication rapide de ce que chaque partie fait:

Les La clause WITH Ancestors AS (...) crée une expression de table commune (essentiellement une sous-requête) portant le nom Ancestors. Le premier SELECT dans cette expression établit une ligne de base: toutes les lignes qui n'ont pas d'entrée correspondante avant elle.

Ensuite, le second est SELECT où la récursion entre en jeu. Comme il fait référence Ancestors dans le cadre de la requête, il utilise les lignes qu'il a déjà ajouté à la table et effectue ensuite une jointure avec de nouvelles de YOUR_TABLE. Cela trouvera récursivement de plus en plus de lignes à ajouter à la fin de chaque chaîne.

La dernière clause est la SELECT qui utilise cette table récursive que nous avons créée. Il fait un simple GROUP BY depuis que nous avons enregistré l'ID d'origine dans la colonne Ancestor, donc le début et la fin sont un simple MIN et MAX.

La partie difficile est de déterminer l'ID de la dernière rangée de la chaîne. Il y a deux façons de le faire, toutes deux illustrées dans la requête. Vous pouvez soit revenir en arrière avec la table récursive, dans ce cas, il construira à nouveau la table récursive, ou vous pouvez essayer de garder une trace du dernier élément que vous allez. (Si la construction de la liste récursive d'enregistrements chaînés est coûteuse, vous voulez certainement minimiser le nombre de fois que vous avez besoin de le faire.)

La façon dont il suit son évolution est de garder une trace de sa position dans la chaîne (la colonne level - remarquez comment nous ajoutons 1 chaque fois que nous recurons), le zéro-pad, puis coller l'ID à la fin. Ensuite, obtenir l'élément avec le maximum level est simplement un MAX suivi de l'effacement des données level.

Si le CTE doit trop se recurer, cela générera une erreur, mais je crois que vous pouvez le modifier en utilisant l'option MAXRECURSION. La valeur par défaut est 100. Si vous devez le définir plus haut, vous pouvez envisager de ne pas utiliser un CTE récursif pour le faire.

Ceci ne gère pas non plus très bien les données malformées. Si vous avez deux enregistrements avec le même first ou un enregistrement où first == end, cela ne fonctionnera pas correctement et vous devrez peut-être modifier les conditions de jointure dans le CTE ou opter pour une autre approche.

Ce n'est pas la seule façon de le faire. Je crois qu'il serait plus facile de suivre si vous avez construit une procédure personnalisée et fait toutes les étapes manuellement. Mais cela a l'avantage de fonctionner dans une seule déclaration.

+0

vous remercie beaucoup. Répondez-vous simple? Je n'utilise que de petites bases de données. –