2010-06-14 7 views
2

J'ai le CTE suivant. Son but est de fournir des paires mois/année uniques. Le code ultérieur utilisera le CTE pour produire une liste de chaînes concaténées des paires Mois/Année.T-SQL - comment contourner l'ordre par restriction dans les CTE

;WITH tblStoredWillsInPeriod AS 
(
    SELECT DISTINCT Kctc.GetMonthAndYearString(DateWillReceived) Month 
    FROM Kctc.StoredWills 
    WHERE DateWillReceived BETWEEN '2010/01/01' AND '2010/03/31' 
    ORDER BY DateWillReceived 
) 

Je l'ai omis implmementation de la fonction GetMonthAndYearString comme il est trivial.

Edit: Comme demandé par Martin, voici le code environnant:

DECLARE @PivotColumnHeaders nvarchar(MAX) 
--CTE declaration as above--- 
SELECT @PivotColumnHeaders = 
    COALESCE(
    @PivotColumnHeaders + ',[' + Month + ']', 
    '[' + Month + ']' 
) 
FROM tblStoredWillsInPeriod 
SELECT @PivotColumnHeaders 

Malheureusement, il semble T-SQL est toujours une longueur d'avance. Quand je lance ce code, il me dit que je ne suis pas autorisé à utiliser ORDER BY dans un CTE sauf si j'utilise aussi TOP (ou FOR XML, quel qu'il soit.) Si j'utilise TOP, il me dit que je ne peux pas l'utiliser avec DISTINCT. Oui, T-SQL a toutes les réponses.

Quelqu'un peut-il penser à une solution à ce problème qui est plus rapide que de simplement couper mes poignets? Je comprends que la mort par la perte de sang peut être étonnamment longue, et j'ai des délais à respecter.

Merci pour votre aide.

David

+0

Pouvez-vous poster le code qui utilise le CTE? Et aussi le format de la valeur renvoyée par GetMonthAndYearString? Vous dites que vous essayez de l'utiliser comme ici http://www.kodyaz.com/articles/t-sql-pivot-tables-in-sql-server-tutorial-with-examples.aspx. Vous êtes conscient qu'un CTE est seulement dans la portée de la déclaration suivante de toute façon? Ainsi, au moment où vous avez rempli @PivotColumnHeaders, il sera hors de portée pour le bit suivant. –

+0

GetMonthAndYearString renvoie un varchar (8) au format MMM-YYYY. Je suis conscient des limites de la portée des CTE - le code environnant que j'ai maintenant fourni des comptes pour cela. – David

Répondre

1

Est-ce que cela fonctionnera?

DECLARE @PivotColumnHeaders VARCHAR(MAX) 

;WITH StoredWills AS 
(
SELECT GETDATE() AS DateWillReceived 
UNION ALL 
SELECT '2010-03-14 11:48:07.580' 
UNION ALL 
SELECT '2010-03-12 11:48:07.580' 
UNION ALL 
SELECT '2010-02-12 11:48:07.580' 
), 
tblStoredWillsInPeriod AS 
(
    SELECT DISTINCT STUFF(RIGHT(convert(VARCHAR, DateWillReceived, 106),8), 4, 1, '-') AS MMMYYYY, 
    DatePart(Year,DateWillReceived) AS Year, 
    DatePart(Month,DateWillReceived) AS Month 
    FROM StoredWills 
    WHERE DateWillReceived BETWEEN '2010-01-01' AND '2010-03-31' 
) 


SELECT @PivotColumnHeaders = 
    COALESCE(
    @PivotColumnHeaders + ',[' + MMMYYYY + ']', 
    '[' + MMMYYYY + ']' 
) 
FROM tblStoredWillsInPeriod 
ORDER BY Year, Month 
+0

Ah, donc la suggestion de Chris Bednarski de quitter le tri du CTE et de le faire dans le code suivant était juste. Je ne pouvais juste pas trouver comment ajouter le tri au bit SELECT ... COALESCE. Merci Martin! – David

+0

Pourrait utiliser DATENAME au lieu de CONVERT. Sinon, juste comme un acheté. +1 –

0

Pourriez-vous expliquer pourquoi vous avez besoin des données du CTE à commander? Et pourquoi vous n'êtes pas en mesure de commander les données dans la requête en utilisant le CTE. Rappelez-vous que les données d'une sous-requête ordinaire ne peuvent pas non plus être commandées.

+0

Bien sûr.La liste des paires mois/année doit être utilisée dans une requête de pivot dynamique. Regardez le dernier exemple ici: http://www.kodyaz.com/articles/t-sql-pivot-tables-in-sql-server-tutorial-with-examples.aspx. Je ne suis pas en mesure de commander les données dans la requête en utilisant le CTE parce que T-SQL me dit que je ne suis pas capable de! Je ne peux pas utiliser la clause ORDER BY. – David

0

Qu'en est-il?

;WITH tblStoredWillsInPeriod AS 
( 
    SELECT DISTINCT Kctc.GetMonthAndYearString(DateWillReceived) Month 
    FROM Kctc.StoredWills 
    WHERE DateWillReceived BETWEEN '2010/01/01' AND '2010/03/31' 
    ORDER BY DateWillReceived 
), 
tblStoredWillsInPeriodOrdered AS 
(
    SELECT TOP 100 PERCENT Month 
    FROM tblStoredWillsInPeriod 
    ORDER BY Month 
) 
+0

Avez-vous un lien qui dit qu'un ORDER BY dans un CTE sera toujours respecté quand il s'agit de SELECT à partir de lui? (En pensant à la déclaration de Jeff Moden ici http://weblogs.sqlteam.com/mladenp/archive/2009/07/28/SQL-Server-2005-Fast-Running-Totals.aspx) –

+0

Merci Chris, je vois où vous êtes venant d'ici. Je ne peux pas commander par mois, car c'est un champ varchar qui ne donnera pas une liste chronologique (par exemple, février 2010 viendra avant janvier 2010). Mais je pourrais construire un champ composé année/mois dans le CTE, puis dans le code suivant, trier par lui. Je vais examiner cela. – David

+0

Non, je n'ai aucun moyen d'utiliser ORDER BY dans le code suivant que je peux voir ... – David

0
SELECT DISTINCT TOP 100 PERCENT ... 
ORDER BY ... 
+0

Vous ne pouvez pas utiliser TOP avec DISTINCT ... – David

+0

Merci pour le heads-up. Je l'ai eu le mauvais chemin. J'ai placé 'DISTINCT' avant 'TOP 100 PERCENT' pour corriger l'erreur de syntaxe. –

0

Et vous pensez que vous connaissez la syntaxe T-SQL!

Il s'avère que j'avais tort de ne pas pouvoir utiliser TOP et DISTINCT ensemble.

Cela donne une erreur de syntaxe ...

SELECT TOP 100 PERCENT DISTINCT... 

alors que cela est tout à fait bien ...

SELECT DISTINCT TOP 100 PERCENT... 

travail qui un. Un inconvénient est que vous devez inclure le champ ORDER BY dans la liste SELECT, ce qui, selon toute probabilité, interférera avec vos résultats DISTINCT attendus. Parfois, T-SQL vous fait tourner en rond.

Mais pour l'instant, mes poignets sont laissés sans marque.

+0

Ah, bien que j'ai découvert que ce n'est pas syntaxiquement valide, les résultats ne sont pas vraiment triés !!! Quelqu'un d'autre? – David

Questions connexes