2010-09-05 6 views
1

En the following:
(. exécution d'une requête sur le Stack Exchange Data Explorer, qui utilise une implémentation SQL Azure de OData Le FAQ dit qu'il supporte la plupart des TSQL commandes):Comment pouvez-vous utiliser des variables ou des références dans SQL?

DECLARE @MinPosts int = ##MinNumberOfPosts## 
SELECT 
    Id AS [User Link], 
    Reputation, 
    (SELECT COUNT(*) 
    FROM posts 
    WHERE posts.OwnerUserId = Users.Id 
    ) AS [# Posts], 
    Reputation/
    (SELECT COUNT(*) 
    FROM posts 
    WHERE posts.OwnerUserId = Users.Id 
    ) AS [Rep Per Post] 
FROM Users 
WHERE (SELECT COUNT(*) 
    FROM posts 
    WHERE posts.OwnerUserId = Users.Id 
    ) > @MinPosts 
ORDER BY [Rep Per Post] DESC 

J'écris:

(SELECT COUNT(*) 
FROM posts 
WHERE posts.OwnerUserId = Users.Id) 

trois fois. Comment puis-je créer une variable ou une fonction pour l'extrait de code ci-dessus?

J'ai essayé d'utiliser l'alias de colonne [# Posts], mais cela n'a pas fonctionné.

J'ai trouvé these posts sur la réutilisation d'un nom de fichier calculé pour un calcul supplémentaire, ce qui semble être ce que je veux, mais je n'arrive pas à comprendre comment l'appliquer.

+1

Quelle saveur de SQL? –

+0

La FAQ dit T-SQL. J'ai tagué en conséquence. – BoltClock

+0

@BoltClock - Merci. On dirait que 'la base de données est hébergée sur SQL Azure. SQL Azure prend en charge la plupart des commandes TSQL –

Répondre

3

Puisque vous avez besoin le compte pour chaque utilisateur dans la base de données complète et donc chaque poste, il suffit de faire de façon directe:

SELECT 
    Id AS [User Link], 
    Reputation, 
    Reputation * 1.0/C.Cnt AS [Rep Per Post] 
FROM 
    Users U 
    INNER JOIN (
     SELECT OwnerUserId, Cnt = Count(*) 
     FROM posts 
     GROUP BY OwnerUserID 
     HAVING Count(*) >= ##MinNumberOfPosts## 
    ) C ON U.Id = C.OwnerUserId 
ORDER BY [Rep Per Post] DESC 

Vous trouverez peut-être Cela donne le même plan d'exécution que la solution CROSS APPLY, mais cela uniquement parce que le moteur est suffisamment intelligent pour éviter la sous-requête corrélée et pour passer à un agrégat simple, comme l'indique explicitement cette requête. Si CROSS APPLY fonctionne vraiment mieux, je suis très intéressé de savoir pourquoi.

post-scriptum J'ai ajouté * 1.0 parce que je devine (pas sûr du moteur ici) que la division entière donne des nombres entiers et il semble que vous voudriez probablement des fractions. Vous devrez expérimenter.

+0

Merci. Je l'ai fait montrer des entiers, juste pour avoir un aspect plus propre. Est-ce que 'Reputation * 1.0' fait la même chose que' CAST (Reputation AS float) '? C'est plus rapide à écrire. –

+1

Je pense que 1.0 est la même chose que la conversion en décimal. Il y a une possibilité qu'il soit très légèrement plus lent qu'un casting explicite, mais je doute qu'il aurait une implication de performance. Décimal vs flotteur ne serait pas une préoccupation à ces fins. – ErikE

1

Vous pouvez utiliser CROSS APPLY,

DECLARE @MinPosts int = ##MinNumberOfPosts## 

SELECT 
    Id AS [User Link], 
    Reputation, 
    counts.[# Posts], 
    Reputation/counts.[# Posts] AS [Rep Per Post] 
FROM Users 
    CROSS APPLY (
    SELECT COUNT(*) 
    FROM posts 
    WHERE posts.OwnerUserId = Users.Id 
) counts([# Posts]) 
WHERE counts.[# Posts] > @MinPosts 
ORDER BY [Rep Per Post] DESC​ 
+0

Merci. C'est exactement ce que je cherchais –

+0

Je ne pense pas que CROSS APPLY soit appelé ici. – ErikE

Questions connexes