Как создать список, разделенный запятыми, с помощью SQL-запроса?
У меня есть 3 таблицы под названием:
- приложения (id, name)
- ресурсы (id, name)
- ApplicationsResources (id, app_id, resource_id)
Я хочу показать на GUI таблицу всех имен ресурсов. В одной ячейке в каждой строке я хотел бы перечислить все приложения (через запятую) этого ресурса.
Итак, вопрос в том, как лучше всего это сделать в SQL, поскольку мне нужно получить все ресурсы, и я также нужно получить все приложения для каждого ресурса?
должен ли я сначала запустить select * from resources, а затем выполнить цикл через каждый ресурс и выполнить отдельный запрос на ресурс, чтобы получить список приложений для этого ресурса?
есть ли способ сделать это в одном запросе?
11 ответов
нет способа сделать это в DB-agnostic способом. Поэтому вам нужно получить весь набор данных следующим образом:
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
и тогда функция concat в AppName программно в то время как группировка по ResName.
в 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
рекомендую читать про строку агрегации/concatentation в Oracle.
использование COALESCE для построения строки с разделителями-запятыми в SQL Server
http://www.sqlteam.com/article/using-coalesce-to-build-comma-delimited-string
пример:
DECLARE @EmployeeList varchar(100)
SELECT @EmployeeList = COALESCE(@EmployeeList + ', ', '') +
CAST(Emp_UniqueID AS varchar(5))
FROM SalesCallsEmployees
WHERE SalCal_UniqueID = 1
SELECT @EmployeeList
Я не знаю, есть ли какое-либо решение для этого агностическим способом базы данных, поскольку вам, скорее всего, понадобится какая-то форма манипуляции строками, и они обычно отличаются между поставщиками.
для SQL Server 2005 и выше можно использовать:
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
он использует SQL Server 2005 FOR XML PATH
построить список подэлементов (приложений для данного ресурса) в виде списка, разделенного запятыми.
Марк
Я верю, что вы хотите:
SELECT ItemName, GROUP_CONCAT(DepartmentId) FROM table_name GROUP BY ItemName
Если вы используете MySQL
ссылка
предполагая SQL Server:
структура таблицы:
CREATE TABLE [dbo].[item_dept](
[ItemName] char(20) NULL,
[DepartmentID] int NULL
)
запрос:
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
результаты:
ItemName DepartmentID
item1 21,13,9,36
item2 4,9,44
Я думаю, что мы могли бы написать следующим образом для извлечения (ниже приведен пример кода, пожалуйста, измените по мере необходимости):
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
С следующая версия SQL Server вы сможете делать
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
для предыдущих версий продукта существует довольно широкий спектр различных подходов к этой проблеме. Отличный отзыв о них есть в статье:объединение значений строк в Transact-SQL.
-
объединение значений, когда количество элементов неизвестно
- рекурсивный метод CTE
- в BlackBox Методы XML
- Использование Общеязыковой Среды Выполнения
- скалярный UDF с рекурсией
- таблица с значением UDF с циклом WHILE
- динамический SQL
- приближение Курсора
.
-
Не-надежных подходов
- скалярный UDF с расширением обновления T-SQL
- скалярный UDF с переменной конкатенацией в 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;
агностиком, и плоскодонки.
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;
теперь пользователь вашего языка программирования сервера для объединения a_names в то время как r_name такой же, как в прошлый раз.
это сделает это в SQL Server:
DECLARE @listStr VARCHAR(MAX)
SELECT @listStr = COALESCE(@listStr+',' ,'') + Convert(nvarchar(8),DepartmentId)
FROM Table
SELECT @listStr