Comment créer une liste séparée par des virgules à l'aide d'une requête SQL?
-
10-07-2019 - |
Question
J'ai 3 tables appelées:
- Applications (identifiant, nom)
- Ressources (identifiant, nom)
- ApplicationsResources (id, id_app, id_ressource)
Je souhaite afficher sur une interface graphique un tableau contenant 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?
Existe-t-il un moyen de faire cela en une seule requête?
La solution
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 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
Ensuite, concatrez le nom_app par programmation lors du regroupement par nom_Résque .
Autres conseils
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 à d'informations sur le regroupement / la concaténation de chaînes dans Oracle .
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-à-construire-chaîne-délimitée
Exemple:
DECLARE @EmployeeList varchar(100)
SELECT @EmployeeList = COALESCE(@EmployeeList + ', ', '') +
CAST(Emp_UniqueID AS varchar(5))
FROM SalesCallsEmployees
WHERE SalCal_UniqueID = 1
SELECT @EmployeeList
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 forme de manipulation de chaîne, et celles-ci sont généralement différentes entre les vendeurs.
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 la construction FOR XML PATH
de SQL Server 2005 pour répertorier les sous-éléments (les applications d'une ressource donnée) sous forme de liste séparée par des virgules.
Marc
Je crois que ce que vous voulez, c'est:
SELECT ItemName, GROUP_CONCAT (DepartmentId) FROM nom_table GROUP BY ItemName
Si vous utilisez MySQL
Référence
En supposant que SQL Server:
Structure de la table:
CREATE TABLE [dbo].[item_dept](
[ItemName] char(20) NULL,
[DepartmentID] int NULL
)
Requête:
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
Je pense que nous pourrions écrire de la manière suivante pour récupérer (le code ci-dessous est un exemple, veuillez le modifier 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
À partir de la version suivante 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 des 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 de la boîte noire
- Utilisation du Common Language Runtime
- UDF scalaire avec récursivité
- Table UDF avec une boucle WHILE
- SQL dynamique
- L'approche du curseur
.
-
Approches non fiables
- UDF scalaire avec extension de mise à jour t-SQL
- Fichier UDF scalaire avec concaténation de variable dans SELECT
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;
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 un nom, alors que nom_r est le même que la dernière fois.
Cela se fera dans SQL Server:
DECLARE @listStr VARCHAR(MAX)
SELECT @listStr = COALESCE(@listStr+',' ,'') + Convert(nvarchar(8),DepartmentId)
FROM Table
SELECT @listStr