J'essaie de migrer une requête d'Oracle vers SQL Server 2014.
Voici ma requête qui fonctionne très bien dans Oracle:
select
count(distinct A) over (partition by B) / count(*) over() as A_B
from MyTable
Voici l'erreur que j'ai reçue après avoir essayé d'exécuter cette requête dans SQL Server 2014.
Use of DISTINCT is not allowed with the OVER clause
Quelqu'un sait quel est le problème? Un tel type de requête est-il possible dans SQL Server? S'il vous plaît donnez votre avis.
Quelqu'un sait quel est le problème? Un tel type de requête est-il possible dans SQL Server?
Non, il n'est pas actuellement implémenté. Voir la demande d'élément de connexion suivante.
demande d'amélioration de la clause OVER - clause DISTINCT pour les fonctions d'agrégation
Une autre variante possible serait
SELECT M.A,
M.B,
T.A_B
FROM MyTable M
JOIN (SELECT CAST(COUNT(DISTINCT A) AS NUMERIC(18,8)) / SUM(COUNT(*)) OVER() AS A_B,
B
FROM MyTable
GROUP BY B) T
ON EXISTS (SELECT M.B INTERSECT SELECT T.B)
le transtypage en NUMERIC
est là pour éviter la division entière. La raison de la clause join est expliquée ici .
Il peut être remplacé par ON M.B = T.B OR (M.B IS NULL AND T.B IS NULL)
si vous préférez (ou simplement ON M.B = T.B
Si la colonne B
n'est pas nullable).
Cela donne le nombre distinct (*) pour A partitionné par B:
dense_rank() over (partition by B order by A)
+ dense_rank() over (partition by B order by A desc)
- 1
Vous pouvez prendre la valeur maximale de dense_rank()
pour obtenir le nombre distinct de A partitionné par B.
Pour prendre en charge le cas où A peut avoir des valeurs nulles, vous pouvez utiliser first_value
pour déterminer si un null est présent dans la partition ou non, puis soustraire 1 s'il est tel que suggéré par Martin Smith dans le commentaire.
select (max(T.DenseRankA) over(partition by T.B) -
cast(iif(T.FirstA is null, 1, 0) as numeric(18, 8))) / T.TotalCount as A_B
from (
select dense_rank() over(partition by T.B order by T.A) DenseRankA,
first_value(T.A) over(partition by T.B order by T.A) as FirstA,
count(*) over() as TotalCount,
T.A,
T.B
from MyTable as T
) as T
Essayez de faire une sous-requête, en regroupant par A, B et en incluant le nombre. Ensuite, dans votre requête externe, votre nombre (distinct) devient un nombre normal et votre nombre (*) devient une somme (cnt).
select
count(A) over (partition by B) * 1.0 /
sum(cnt) over() as A_B
from
(select A, B, count(*) as cnt
from MyTable
group by A, B) as partial;
Pour l'instant, SQL Server ne permet pas d'utiliser Distinct
avec des fonctions fenêtrées.
Mais une fois que vous vous souvenez du fonctionnement des fonctions fenêtrées (c'est-à-dire qu'elles sont appliquées au jeu de résultats de la requête), vous pouvez contourner cela:
select B,
min(count(distinct A)) over (partition by B) / max(count(*)) over() as A_B
from MyTable
group by B