Je crée un forum, j'ai donc créé une table avec des posts. L'un des champs est un Body
avec le type XML
. Maintenant, je voudrais créer une requête qui renvoie tous les messages et le nombre d'enfants de chaque post. Je fais cela avec une fonction d'agrégat. J'ai besoin d'utiliser un groupe lorsque j'utilise la fonction agrégée. Lorsque j'utilise le champ dans le group by
, j'obtiens l'exception suivante:
Le type de données XML ne peut pas être comparé ou sortingé, sauf lors de l'utilisation de l'opérateur IS NULL.
Comment puis-je resoudre ceci?
Ma question est:
SELECT Post.PostId, Post.[Body], Count(Children.PostId) FROM dbo.Post Post, dbo.Post Children WHERE Children.ParentId = Post.PostId GROUP BY Post.PostId, Post.[Body]
Vous pouvez faire l'agrégation dans un CTE puis vous joindre à cela
WITH Children(Cnt, ParentId) AS (SELECT COUNT(*), ParentId FROM dbo.Post GROUP BY ParentId) SELECT P.PostId, P.[Body], ISNULL(Cnt, 0) AS Cnt FROM dbo.Post P LEFT JOIN Children /*To include childless posts*/ ON Children.ParentId = P.PostId ORDER BY P.PostId
Pouvez-vous faire le Group par sans sélectionner le champ XML, dans une sous-requête, puis select le champ XML, et les autres colonnes se joignant à votre sous-requête?
En utilisant votre requête, vous obtiendrez: par exemple
SELECT Post.[Body], sq.* FROM ( SELECT Post.PostId, Count(Children.PostId) FROM dbo.Post Post, dbo.Post Children WHERE Children.ParentId = Post.PostId GROUP BY Post.PostId ) as sq INNER JOIN Post on Post.PostId= sq.PostId
Cependant, vous utilisez une jointure join / ansi ici, ce qui n'est pas la meilleure façon de le faire. Une meilleure façon serait:
SELECT Post.[Body], sq.* FROM ( SELECT Post.PostId, Count(Children.PostId) FROM dbo.Post Post LEFT OUTER JOIN Children on Children.ParentId = Post.PostId GROUP BY Post.PostId ) as sq INNER JOIN Post on Post.PostId= sq.PostId
essayer de cette façon espère que cela vous aidera
SELECT Post.PostId, Post.[Body], Count(Children.PostId) over() as totalids FROM dbo.Post Post, dbo.Post Children WHERE Children.ParentId = Post.PostId
comme j'ai travaillé vérifier ceci
create table xmltable (attr1 int identity ,attr2 varchar(50),attr3 xml) insert into xmltable select 'i',(SELECT ( SELECT 'sometext' FOR XML PATH('body'),TYPE)FOR XML PATH(''),ROOT('SampleXML')) union all select 'j',(SELECT ( SELECT 'sometext' FOR XML PATH('body'),TYPE)FOR XML PATH(''),ROOT('SampleXML')) union all select 'k',(SELECT ( SELECT 'sometext' FOR XML PATH('body'),TYPE)FOR XML PATH(''),ROOT('SampleXML')) union all select 'l',(SELECT ( SELECT 'sometext' FOR XML PATH('body'),TYPE)FOR XML PATH(''),ROOT('SampleXML')) create table xmlid (x int ,y varchar(50)) insert into xmlid select 1,'x' union all select 1,'y' union all select 2,'z' union all select 2,'xyz1' union all select 3,'xyz2' union all select 1,'xyz3' select * from xmltable select * from xmlid
créer des tables puis
select * from xmltable select * from xmlid select attr1,attr2, attr3,count(attr1) over(partition by attr2 ) as total_qtyover from xmltable a,xmlid b where a.attr1=bx
voir aussi ceci Comment aggréger sans utiliser "GROUP BY"?
Je décomposerais en deux requêtes, une pour get les identifiants et les counts d'enfants, et une autre pour get les corps. Pour effectuer un GROUP BY
le server doit sortinger les champs de regroupement. Vous pouvez donc déplacer et comparer un grand nombre de données lorsque vous n'en avez pas besoin (à less que vous n'ayez plusieurs corps de post avec le même ID).