Come faccio a creare un elenco separato da virgole utilizzando una query SQL?
-
10-07-2019 - |
Domanda
Ho 3 tabelle chiamate:
- Applicazioni (ID, nome)
- Risorse (ID, nome)
- ApplicationsResources (id, app_id, resource_id)
Voglio mostrare su una GUI una tabella con tutti i nomi delle risorse. In una cella di ogni riga vorrei elencare tutte le applicazioni (separate da virgola) di quella risorsa.
Quindi la domanda è: qual è il modo migliore per farlo in SQL in quanto ho bisogno di ottenere tutte le risorse e ho anche bisogno di ottenere tutte le applicazioni per ogni risorsa?
Eseguo prima una selezione * dalle risorse, quindi eseguo il ciclo attraverso ciascuna risorsa ed eseguo una query separata per risorsa per ottenere l'elenco delle applicazioni per quella risorsa?
Esiste un modo per farlo in una query?
Soluzione
Non c'è modo di farlo in modo indipendente dal DB. Quindi è necessario ottenere l'intero set di dati in questo modo:
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
E quindi concatena NomeApp a livello di programmazione mentre raggruppate per ResName .
Altri suggerimenti
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
Raccomando leggere informazioni sull'aggregazione / concatenazione di stringhe in Oracle .
Utilizzo di COALESCE per creare una stringa delimitata da virgole in SQL Server
http://www.sqlteam.com/article/using -coalesce-to-build-delimitato da virgole-string
Esempio:
DECLARE @EmployeeList varchar(100)
SELECT @EmployeeList = COALESCE(@EmployeeList + ', ', '') +
CAST(Emp_UniqueID AS varchar(5))
FROM SalesCallsEmployees
WHERE SalCal_UniqueID = 1
SELECT @EmployeeList
Non so se esiste una soluzione per farlo in modo indipendente dal database, dal momento che molto probabilmente avrai bisogno di una qualche forma di manipolazione delle stringhe, e queste sono generalmente diverse tra i fornitori.
Per SQL Server 2005 e versioni successive, è possibile utilizzare:
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
Utilizza il costrutto FOR XML PATH
di SQL Server 2005 per elencare i componenti secondari (le applicazioni per una determinata risorsa) come un elenco separato da virgole.
Marc
Credo che ciò che vuoi sia:
SELECT ItemName, GROUP_CONCAT (DepartmentId) FROM table_name GROUP BY ItemName
Se stai usando MySQL
Riferimento
Supponendo SQL Server:
Struttura della tabella:
CREATE TABLE [dbo].[item_dept](
[ItemName] char(20) NULL,
[DepartmentID] int NULL
)
Domanda:
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
Risultati:
ItemName DepartmentID
item1 21,13,9,36
item2 4,9,44
Penso che potremmo scrivere nel seguente modo per recuperare (sotto il codice è solo un esempio, si prega di modificare secondo necessità):
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
Da prossima versione di SQL Server sarai in grado di fare
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
Per le versioni precedenti del prodotto esiste una grande varietà di approcci diversi a questo problema. Un'ottima recensione è nell'articolo: Concatenazione dei valori di riga in Transact-SQL .
-
Concatenamento di valori quando il numero di elementi non è noto
- Metodo CTE ricorsivo
- I metodi XML della blackbox
- Uso di Common Language Runtime
- UDF scalare con ricorsione
- UDF valutato in tabella con un ciclo WHILE
- SQL dinamico
- L'approccio del cursore
.
-
Approcci non affidabili
- UDF scalare con estensione di aggiornamento t-SQL
- UDF scalare con concatenazione variabile in 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;
Per essere agnostici, torna indietro e 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;
Ora usa il tuo linguaggio di programmazione del server per concatenare a_names mentre r_name è lo stesso dell'ultima volta.
Questo lo farà in SQL Server:
DECLARE @listStr VARCHAR(MAX)
SELECT @listStr = COALESCE(@listStr+',' ,'') + Convert(nvarchar(8),DepartmentId)
FROM Table
SELECT @listStr