2009-09-06 7 views
0

Je possède ce tableauSQL Server CTE récursive et la pagination

CREATE TABLE [dbo].[friend_blocked_list](
[subdomain] [varchar](50) NOT NULL, 
[un] [nvarchar](50) NOT NULL, 
[friend] [nvarchar](50) NOT NULL, 
[is_blocked] [bit] NOT NULL, 
[approved] [bit] NOT NULL) 

où je sélectionne des données avec de dessous requête. Sélectionnez requête combine utilisateurs ajoutés par l'utilisateur comme ami et les utilisateurs qui ont été ajoutés comme ami par l'utilisateur

declare @un varchar(50), @subdomain varchar(50) 

set @un='user2'; 
set @subdomain ='test.domain.com'; 

WITH FRIENDS as 
(
    SELECT friend 
    FROM friend_blocked_list 
    WHERE [email protected] and [email protected] and approved=1 and is_blocked=0 

    UNION ALL 

    SELECT un as friend 
    FROM friend_blocked_list 
    WHERE [email protected] and [email protected] and approved=1 and is_blocked=0 
) 
select friend from FRIENDS group by FRIENDS.friend order by FRIENDS.friend asc 

Il fonctionne très bien avec une petite amout de données, mais je veux être en mesure de faire une recherche de personnes sur le côté serveur afin pour réduire la charge. J'essaie de le combiner avec mon paging sp ci-dessous

create PROCEDURE [dbo].[Paging] 
    @subdomain varchar(50), 
    @un varchar(50), 
    @PageNumber int, 
    @PageSize int 
AS 
BEGIN 
    --paging 
    DECLARE @FirstRow INT,@LastRow INT,@RowCount INT,@PageCount INT 

    --find recordcount and pages 
    SELECT @RowCount = COUNT(*), @PageCount = COUNT(*)/@PageSize 
    FROM friend_blocked_list 
    WHERE [email protected] AND [email protected] AND approved=1 AND is_blocked=0; 

    --- calculate pages  
    IF @RowCount % @PageSize != 0 SET @PageCount = @PageCount + 1 
    IF @PageNumber < 1 SET @PageNumber = 1 
    IF @PageNumber > @PageCount SET @PageNumber = @PageCount 

    SELECT 
     CurrentPage = @PageNumber, 
     TotalPages = @PageCount, 
     TotalRows = @RowCount 

    -- mora calculation 
    SELECT @FirstRow = (@PageNumber - 1) * @PageSize + 1, 
      @LastRow = (@PageNumber - 1) * @PageSize + @PageSize ; 

    WITH MyTopics AS 
    (
     SELECT *, ROW_NUMBER() OVER (order by un asc) AS RowNumber 
     FROM friend_blocked_list 
     WHERE [email protected] AND [email protected] AND approved=1 AND is_blocked=0 
    ) 
    SELECT * 
    FROM MyTopics 
    WHERE RowNumber BETWEEN @FirstRow AND @LastRow 
    ORDER BY RowNumber ASC; 
end 

Mais comme toujours j'ai des problèmes :). Le principal problème est le UNION ALL dans ma requête. Il m'empêche d'utiliser ROW_NUMBER() OVER.

Des idées?

Répondre

1

Voici votre procédure mis à jour pour la pagination:

CREATE PROCEDURE [dbo].[Paging] 
    @subdomain varchar(50), 
    @un varchar(50), 
    @PageNumber int, 
    @PageSize int 
AS 

    DECLARE @start_row int 
    DECLARE @end_row int 

    SET @end_row = @PageNumber * @PageSize 
    SET @start_row = @end_row - (@PageSize - 1) 

BEGIN 

    WITH FRIENDS AS (
    SELECT t.friend 
     FROM FRIEND_BLOCKED_LIST t 
    WHERE t.un = @un 
     AND t.subdomain = @subdomain 
     AND t.approved = 1 
     AND t.is_blocked = 0 
    UNION ALL 
    SELECT t.un as friend 
     FROM FRIEND_BLOCKED_LIST t 
    WHERE t.friend = @un 
     AND t.subdomain = @subdomain 
     AND t.approved = 1 
     AND t.is_blocked = 0) 
SELECT t.friend 
    FROM (SELECT f.friend, 
       ROW_NUMBER() OVER (ORDER BY f.friend) AS rownum 
      FROM FRIENDS f 
     GROUP BY f.friend) t 
WHERE t.rownum BETWEEN @start_row AND @end_row 

END 

Il pourrait être possible de changer la requête d'utiliser un CTE si vous pouvez fournir plus d'informations sur le tableau FRIEND_BLOCKED_LIST. Le UNION de deux requêtes avec des clauses WHERE identiques tout en faisant la différence entre deux colonnes me fait me demander s'il ne pourrait pas être mieux écrit. le CTE AMIS pourrait être réécrite comme:

SELECT COALESCE(t.un, t.friend) as friend 
    FROM FRIEND_BLOCKED_LIST t 
WHERE @un = COALESCE(t.un, t.friend) 
    AND t.subdomain = @subdomain 
    AND t.approved = 1 
    AND t.is_blocked = 0 
+0

Quel genre d'information auriez-vous besoin sur la table FRIEND_BLOCKED_LIST? – nLL

+0

également dans le deuxième sélectionnez après l'union tout ce qu'il devrait être OÙ t.friend = @UN istead de OÙ t.un = @UN ne sont donc pas des requêtes identiques – nLL

+0

liste de colonne si elle est pas très longue et quelle est votre logique pour UNION sur FRIEND_BLOCKED_LIST. La requête en l'état ressemble à renvoyer FRIEND_BLOCKED_LIST.friend et FRIEND_BLOCKED_LIST.un pour la même personne (?). Ce n'est pas clair ce qui se passe dans la table. –

0

Appliquer le numéro de ligne à la liste que vous souhaitez revenir:

WITH FRIENDS as 
(
SELECT friend 
    FROM friend_blocked_list 
    WHERE [email protected] and [email protected] and approved=1 and is_blocked=0 
UNION ALL 
SELECT un as friend 
    FROM friend_blocked_list 
    WHERE [email protected] and [email protected] and approved=1 and is_blocked=0) 
, recursive_friends as (
select friend 
, row_number() over (order by friend asc) as rn 
from FRIENDS) 
select friend 
    from recursive_friends 
    where rn between @firstRow and @lastRow 
    order by FRIENDS.friend asc; 
+0

, recursive_friends comme (choisir ami, row_number() sur (l'ordre par un ami asc) comme des amis de rnfrom) ne semble pas avoir raison – nLL