web-dev-qa-db-fra.com

Comment créer une liste séparée par des virgules à l'aide d'une requête SQL?

J'ai 3 tables appelées:

  • Applications (identifiant, nom)
  • Ressources (identifiant, nom)
  • ApplicationsResources (id, app_id, resource_id)

Je veux montrer sur une interface graphique une table de tous les noms de ressources. Dans une cellule de chaque ligne, j'aimerais répertorier toutes les applications (séparées par des virgules) de cette ressource.

La question est donc de savoir quel est le meilleur moyen de le faire en SQL, car je dois obtenir toutes les ressources et obtenir toutes les applications pour chaque ressource.

Dois-je d'abord exécuter une sélection de ressources, puis parcourir chaque ressource et effectuer une requête distincte par ressource pour obtenir la liste des applications de cette ressource?

Est-il possible de le faire en une seule requête?

53
leora

Il n'y a aucun moyen de le faire d'une manière agnostique à la base de données. Vous devez donc obtenir l'ensemble de données complet comme ceci:

select 
  r.name as ResName, 
  a.name as AppName
from 
  Resouces as r, 
  Applications as a, 
  ApplicationsResources as ar
where
  ar.app_id = a.id 
  and ar.resource_id = r.id

Et ensuite concattez le AppNamepar programme lors du regroupement par ResName.

0
Dmytrii Nagirniak

MySQL

  SELECT r.name,
         GROUP_CONCAT(a.name SEPARATOR ',')
    FROM RESOURCES r
    JOIN APPLICATIONSRESOURCES ar ON ar.resource_id = r.id
    JOIN APPLICATIONS a ON a.id = ar.app_id
GROUP BY r.name

SQL Server (2005+)

SELECT r.name,
       STUFF((SELECT ','+ a.name
               FROM APPLICATIONS a
               JOIN APPLICATIONRESOURCES ar ON ar.app_id = a.id
              WHERE ar.resource_id = r.id
           GROUP BY a.name
            FOR XML PATH(''), TYPE).value('.','VARCHAR(max)'), 1, 1, '')
 FROM RESOURCES r

SQL Server (2017+)

  SELECT r.name,
         STRING_AGG(a.name, ',')
    FROM RESOURCES r
    JOIN APPLICATIONSRESOURCES ar ON ar.resource_id = r.id
    JOIN APPLICATIONS a ON a.id = ar.app_id
GROUP BY r.name

Oracle

Je recommande lecture sur l'agrégation/concaténation de chaînes dans Oracle .

115
OMG Ponies

Utilisation de COALESCE pour créer une chaîne délimitée par des virgules dans SQL Server
http://www.sqlteam.com/article/using-coalesce-to-build-comma-delimited-string

Exemple:

DECLARE @EmployeeList varchar(100)

SELECT @EmployeeList = COALESCE(@EmployeeList + ', ', '') + 
   CAST(Emp_UniqueID AS varchar(5))
FROM SalesCallsEmployees
WHERE SalCal_UniqueID = 1

SELECT @EmployeeList
26
Robert Harvey

Je ne sais pas s'il existe une solution pour le faire d'une manière agnostique à la base de données, car vous aurez probablement besoin d'une certaine forme de manipulation de chaîne, et celles-ci sont généralement différentes entre les fournisseurs.

Pour SQL Server 2005 et versions ultérieures, vous pouvez utiliser:

SELECT
     r.ID, r.Name,
     Resources = STUFF(
       (SELECT ','+a.Name
        FROM dbo.Applications a
        INNER JOIN dbo.ApplicationsResources ar ON ar.app_id = a.id
        WHERE ar.resource_id = r.id
        FOR XML PATH('')), 1, 1, '')
FROM
     dbo.Resources r

Il utilise le SQL Server 2005 FOR XML PATH construction pour lister les sous-éléments (les applications d’une ressource donnée) en tant que liste séparée par des virgules.

Marc

11
marc_s

Je crois que ce que tu veux c'est:

SELECT ItemName, GROUP_CONCAT(DepartmentId) FROM table_name GROUP BY ItemName

Si vous utilisez MySQL

Référence

5
Jamie Wong

En supposant que SQL Server:

Structure de la table:

CREATE TABLE [dbo].[item_dept](
    [ItemName] char(20) NULL,
    [DepartmentID] int NULL   
)

Question:

SELECT ItemName,
       STUFF((SELECT ',' + rtrim(convert(char(10),DepartmentID))
        FROM   item_dept b
        WHERE  a.ItemName = b.ItemName
        FOR XML PATH('')),1,1,'') DepartmentID
FROM   item_dept a
GROUP BY ItemName

Résultats:

ItemName    DepartmentID
item1       21,13,9,36
item2       4,9,44
5
Kenneth

Je pense que nous pourrions écrire de la manière suivante pour récupérer (le code ci-dessous n'est qu'un exemple, modifiez-le au besoin):

Create FUNCTION dbo.ufnGetEmployeeMultiple(@DepartmentID int)
RETURNS VARCHAR(1000) AS

BEGIN

DECLARE @Employeelist varchar(1000)

SELECT @Employeelist = COALESCE(@Employeelist + ', ', '') + E.LoginID
FROM humanresources.Employee E

Left JOIN humanresources.EmployeeDepartmentHistory H ON
E.BusinessEntityID = H.BusinessEntityID

INNER JOIN HumanResources.Department D ON
H.DepartmentID = D.DepartmentID

Where H.DepartmentID = @DepartmentID

Return @Employeelist

END

SELECT D.name as Department, dbo.ufnGetEmployeeMultiple (D.DepartmentID)as Employees
FROM HumanResources.Department D

SELECT Distinct (D.name) as Department, dbo.ufnGetEmployeeMultiple (D.DepartmentID) as 
Employees
FROM HumanResources.Department D
4
user1696097

De prochaine version de SQL Server vous pourrez faire

SELECT r.name,
       STRING_AGG(a.name, ',')
FROM   RESOURCES r
       JOIN APPLICATIONSRESOURCES ar
         ON ar.resource_id = r.id
       JOIN APPLICATIONS a
         ON a.id = ar.app_id
GROUP  BY r.name 

Les versions précédentes du produit offrent une grande variété d'approches différentes à ce problème. Vous trouverez une excellente critique d’eux dans l’article: Concaténation de valeurs de ligne dans Transact-SQL .

  • Concaténer des valeurs lorsque le nombre d'éléments n'est pas connu

    • Méthode CTE récursive
    • Les méthodes XML Blackbox
    • Utilisation du Common Language Runtime
    • UDF scalaire avec récursion
    • Table UDF avec une boucle WHILE
    • SQL dynamique
    • L'approche du curseur
      .
  • Approches non fiables

    • Scalar UDF avec extension de mise à jour t-SQL
    • UDF scalaire avec concaténation variable dans SELECT
4
Martin Smith

MySQL

  SELECT r.name,
         GROUP_CONCAT(a.name SEPARATOR ',')
    FROM RESOURCES r
    JOIN APPLICATIONSRESOURCES ar ON ar.resource_id = r.id
    JOIN APPLICATIONS a ON a.id = ar.app_id
GROUP BY r.name

**


MS SQL Server

SELECT r.name,
       STUFF((SELECT ','+ a.name
               FROM APPLICATIONS a
               JOIN APPLICATIONRESOURCES ar ON ar.app_id = a.id
              WHERE ar.resource_id = r.id
           GROUP BY a.name
            FOR XML PATH(''), TYPE).value('.','VARCHAR(max)'), 1, 1, '')
 FROM RESOURCES r
 GROUP BY deptno;

Oracle

  SELECT r.name,
         LISTAGG(a.name SEPARATOR ',') WITHIN GROUP (ORDER BY a.name)
  FROM RESOURCES r
        JOIN APPLICATIONSRESOURCES ar ON ar.resource_id = r.id
        JOIN APPLICATIONS a ON a.id = ar.app_id
  GROUP BY r.name;
2
Pavel Zimogorov

Cela le fera dans SQL Server:

DECLARE @listStr VARCHAR(MAX)
SELECT @listStr = COALESCE(@listStr+',' ,'') + Convert(nvarchar(8),DepartmentId)
FROM Table
SELECT @listStr
1
Abe Miessler

Pour être agnostique, redescendre et punt.

Select a.name as a_name, r.name as r_name
  from ApplicationsResource ar, Applications a, Resources r
 where a.id = ar.app_id
   and r.id = ar.resource_id
 order by r.name, a.name;

Maintenant, utilisez votre langage de programmation serveur pour concaténer a_names alors que r_name est identique à la dernière fois.

1
Don