2010-11-02 27 views
9

Je dois créer une vue à partir de plusieurs tables. Une des colonnes de la vue devra être composée d'un nombre de lignes de l'une des tables sous la forme d'une chaîne avec des valeurs séparées par des virgules.Utilisation de COALESCE dans la vue SQL

Voici un exemple simplifié de ce que je veux faire.

Customers: 
CustomerId int 
CustomerName VARCHAR(100) 

Orders: 
CustomerId int 
OrderName VARCHAR(100) 

Il existe une relation un-à-plusieurs entre Client et Commandes. Donc, étant donné ces données

Customers 
1 'John' 
2 'Marry' 

Orders 
1 'New Hat' 
1 'New Book' 
1 'New Phone' 

Je veux une vue d'être comme ceci:

Name  Orders 
'John' New Hat, New Book, New Phone 
'Marry' NULL 

Alors que tout le monde apparaît dans la table, indépendamment du fait qu'ils ont des ordres ou non.

J'ai une procédure stockée que j'ai besoin de traduire à cette vue, mais il semble que vous ne pouvez pas déclarer les paramètres et appeler les process stockés dans une vue. Des suggestions sur la façon d'obtenir cette requête dans une vue?

CREATE PROCEDURE getCustomerOrders(@customerId int) 
AS 
    DECLARE @CustomerName varchar(100) 
    DECLARE @Orders varchar (5000) 

    SELECT @Orders=COALESCE(@Orders,'') + COALESCE(OrderName,'') + ',' 
    FROM Orders WHERE [email protected] 

    -- this has to be done separately in case orders returns NULL, so no customers are excluded 
    SELECT @CustomerName=CustomerName FROM Customers WHERE [email protected] 

    SELECT @CustomerName as CustomerName, @Orders as Orders 
+1

Quelle version de SQL Server vous avoir? – David

+0

SQL Server 2008 – kateroh

Répondre

9

EDIT: Réponse modifiée pour inclure la création de vue.

/* Set up sample data */ 
create table Customers (
    CustomerId int, 
    CustomerName VARCHAR(100) 
) 

create table Orders (
    CustomerId int, 
    OrderName VARCHAR(100) 
) 

insert into Customers 
    (CustomerId, CustomerName) 
    select 1, 'John' union all 
    select 2, 'Marry' 

insert into Orders 
    (CustomerId, OrderName) 
    select 1, 'New Hat' union all 
    select 1, 'New Book' union all 
    select 1, 'New Phone' 
go 

/* Create the view */  
create view OrderView as  
    select c.CustomerName, x.OrderNames 
     from Customers c 
      cross apply (select stuff((select ',' + OrderName from Orders o where o.CustomerId = c.CustomerId for xml path('')),1,1,'') as OrderNames) x 
go 

/* Demo the view */ 
select * from OrderView 
go 

/* Clean up after demo */ 
drop view OrderView 
drop table Customers 
drop table Orders 
go 
+0

Doux, ça a marché comme par magie! Je viens d'ajouter DISTINCT à la première déclaration select et c'est prêt à servir. Merci! – kateroh

+0

Mmmmm. Le bookmarking celui-ci pour référence future ... :) –

+0

Le seul problème avec mon cette instruction sql est que vous ne pouvez pas faire une vue avec une telle déclaration indexée comme CROSS APPLY n'est pas autorisée pour les vues indexées. Toute suggestion sur la façon de transformer une vue avec cette sélection en une vue favorable à l'index? Merci! – kateroh

6

Dans SQL Server 2008, vous pouvez profiter de quelques-unes des fonctionnalités supplémentaires pour XML faire tout cela dans une requête sans l'aide d'un proc stocké:

SELECT CustomerName, 
    STUFF(-- "STUFF" deletes the leading ', ' 
     (SELECT ', ' + OrderName 
     FROM Orders 
     WHERE CustomerId = Customers.CutomerId 
     -- This causes the sub-select to be returned as a concatenated string 
     FOR XML PATH('') 
     ), 
    1, 2, '') 
    AS Orders 
FROM Customers 
+0

Comme David ... utilisez cette méthode XML tout le temps pour créer des chaînes. – scarpacci

+0

Bel exemple court et succinct - j'ai pu l'appliquer immédiatement. À votre santé! – wloescher