¿Cómo creo una lista separada por comas usando una consulta SQL?
-
10-07-2019 - |
Pregunta
Tengo 3 tablas llamadas:
- Aplicaciones (id, nombre)
- Recursos (id, nombre)
- AplicacionesRecursos (id, app_id, resource_id)
Quiero mostrar en una GUI una tabla de todos los nombres de recursos. En una celda de cada fila, me gustaría enumerar todas las aplicaciones (separadas por comas) de ese recurso.
Entonces, la pregunta es, ¿cuál es la mejor manera de hacer esto en SQL, ya que necesito obtener todos los recursos y también necesito obtener todas las aplicaciones para cada recurso?
¿Ejecuto un select * de los recursos primero y luego recorro cada recurso y hago una consulta por recurso por separado para obtener la lista de aplicaciones para ese recurso?
¿Hay alguna manera de hacer esto en una consulta?
Solución
No hay forma de hacerlo de una manera independiente de DB. Por lo tanto, debe obtener todo el conjunto de datos de esta manera:
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
Y luego concat el AppName programáticamente mientras se agrupa por ResName .
Otros consejos
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
Oráculo
Recomiendo leer sobre la agregación / concatenación de cadenas en Oracle .
Uso de COALESCE para construir cadenas delimitadas por comas en SQL Server
http://www.sqlteam.com/article/using -coalesce-to-build-comma-delimited-string
Ejemplo:
DECLARE @EmployeeList varchar(100)
SELECT @EmployeeList = COALESCE(@EmployeeList + ', ', '') +
CAST(Emp_UniqueID AS varchar(5))
FROM SalesCallsEmployees
WHERE SalCal_UniqueID = 1
SELECT @EmployeeList
No sé si hay alguna solución para hacer esto de una manera independiente de la base de datos, ya que lo más probable es que necesites alguna forma de manipulación de cadenas, y esas son típicamente diferentes entre los proveedores.
Para SQL Server 2005 y versiones posteriores, puede usar:
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
Utiliza la construcción FOR XML PATH
de SQL Server 2005 para enumerar los subelementos (las aplicaciones para un recurso dado) como una lista separada por comas.
Marc
Creo que lo que quieres es:
SELECT ItemName, GROUP_CONCAT (DepartmentId) FROM table_name GROUP BY ItemName
Si estás usando MySQL
Referencia
Asumiendo SQL Server:
Estructura de tabla:
CREATE TABLE [dbo].[item_dept](
[ItemName] char(20) NULL,
[DepartmentID] int NULL
)
Consulta:
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
Resultados:
ItemName DepartmentID
item1 21,13,9,36
item2 4,9,44
Creo que podríamos escribir de la siguiente manera para recuperar (el siguiente código es solo un ejemplo, modifíquelo según sea necesario):
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
Desde próxima versión de SQL Server podrá hacer
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
Para versiones anteriores del producto, existe una gran variedad de enfoques diferentes para este problema. Una excelente revisión de ellos está en el artículo: Concatenación de valores de fila en Transact-SQL .
-
Concatenación de valores cuando no se conoce el número de elementos
- Método CTE recursivo
- Los métodos XML de blackbox
- Uso de Common Language Runtime
- UDF escalar con recursividad
- Tabla con valor UDF con un ciclo WHILE
- SQL dinámico
- El enfoque del cursor
.
-
Enfoques no confiables
- UDF escalar con extensión de actualización t-SQL
- UDF escalar con concatenación variable en SELECCIONAR
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
**
Servidor MS SQL
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;
Para ser agnóstico, retroceda y despeje.
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;
Ahora usa el lenguaje de programación de tu servidor para concatenar a_names mientras que r_name es el mismo que la última vez.
Esto lo hará en SQL Server:
DECLARE @listStr VARCHAR(MAX)
SELECT @listStr = COALESCE(@listStr+',' ,'') + Convert(nvarchar(8),DepartmentId)
FROM Table
SELECT @listStr