#sql #sql-server #vb.net #visual-studio #many-to-many
#sql #sql-server #vb.net #visual-studio #многие ко многим
Вопрос:
Пожалуйста, мне нужна помощь. Я создал таблицу Users
(столбцы UserID
, UserName
) и таблицу Project
(столбцы ProjectID
, ProjectName
) и таблицу мостов, в которой отображаются имя проекта и имя пользователя.
В каждом проекте более одного пользователя, и каждый пользователь может участвовать в нескольких проектах.
Таблица мостов выглядит следующим образом:
Доступно ли такое представление даты и как?
Обратите внимание, что проекты и имена пользователей не являются фиксированными, они динамичны, они добавляются из форм в VB.NET .
Комментарии:
1. tutorialspoint.com/sql/sql-using-joins.htm
2. @michael raouf у вас определено количество столбцов? т.е. сколько максимальных пользователей может иметь один проект?
3. Нет максимального количества пользователей, мне нужно быть динамичным, я думаю, что это не логично, но я пытаюсь, доступно ли это
4. Я просто хочу просмотреть всех пользователей в одном проекте в простом представлении
Ответ №1:
могу ли я предложить следующее решение (пожалуйста, не судите слишком строго, это просто идея): вместо того, чтобы использовать фиктивное «Имя пользователя» в качестве имени столбца в вашей первой строке, почему бы не поместить туда реальные имена пользователей и иметь метки «да» / «нет» при пересечении строки / столбца для каждого пользователя /проект. Смотрите рисунок ниже. Это обычный тип представления в различных таблицах членства или таблицах подсчета очков игроков (но они имеют одинаковые имена по вертикали и горизонтали).
Я вставил тестовые записи о членстве, чтобы вы видели, что Марк является участником во всех проектах, а Брайан — только в SQL.
Этот динамический SQL выдает приведенный выше результат:
DECLARE @dynPivotSQL AS NVARCHAR(MAX)
DECLARE @pivotColNames AS NVARCHAR(MAX)
DECLARE @pivotColNamesMin AS NVARCHAR(MAX)
-- get distinct username for column headers
SELECT @pivotColNames= ISNULL(@pivotColNames ',','')
QUOTENAME(UserName),
@pivotColNamesMin= ISNULL(@pivotColNamesMin ',','')
'min(' QUOTENAME(UserName) ') as ' QUOTENAME(UserName)
FROM (SELECT DISTINCT UserName, UserID FROM Users) AS U
SET @dynPivotSQL = N'
with cte as (
select p.ProjectName,u.UserName,IsMember=1 from ProjectsUsers pu
join Projects p on p.ProjectID = pu.FK_ProjectID
join Users u on u.UserID = pu.FK_UserID
) select ProjectName, ' @pivotColNamesMin ' from cte
pivot (
min(IsMember) for UserName in (' @pivotColNames ')
) pvt
group by ProjectName '
EXEC sp_executesql @dynPivotSQL
Обратите внимание, поскольку вашим требованием является наличие динамических списков проектов / пользователей, мне пришлось использовать динамический sql для создания динамического списка столбцов для T-SQL PIVOT, который обычно работает с жестко заданными / статическими значениями / именами столбцов.
Обратите внимание, что в используемом блоке pivot также есть трюк min(IsMember), поскольку для pivot требуется некоторая включенная агрегатная функция, но мы не можем использовать min(UserName), потому что он действительно вернет минимальное имя в наборе конкретных имен участников проекта.
@pivotColNamesMin — это еще один трюк, теперь для GROUP BY, потому что он не будет выполняться, если все возвращаемые столбцы не находятся в списке group by или не находятся внутри агрегатной функции.
Я уверен, что вы можете передать предлагаемый источник данных в свою таблицу данных, и во время некоторых событий ItemDataBound или подобных событий вы можете изменить эти метки «1» на пользовательские строки или изображения с помощью «YES» или что-нибудь в этом роде. Но для того, чтобы это работало, ваша databrid не должна использовать жестко заданные имена столбцов и иметь возможность динамически загружать их из фактического набора результатов.
Я протестировал свой запрос на SQL Server 2008 R2. Дайте мне знать, является ли это приемлемым решением, чтобы я мог прекратить его настройку.
HTH
Ответ №2:
Спасибо, ребята, я нашел другое решение, выбрав название проекта из списка со списком, а в таблице отобразите имена пользователей, которые они участвуют в этих проектах, это не похоже на то, что я хочу в первом, но это решение более простое: D еще раз спасибо
Комментарии:
1. спасибо за обратную связь! Обратите внимание, что в будущем, если вам нужно превратить строки в столбцы, используйте предложение PIVOT и основывайтесь на нем.
Ответ №3:
Я создал таблицу в SQL Server с показанными вами записями и VB.NET консольное приложение с этим кодом:
Option Infer On
Imports System.Data.SqlClient
Module Module1
Sub Main()
Dim csb As New SqlConnectionStringBuilder With {.DataSource = ".SQLEXPRESS", .InitialCatalog = "testing", .IntegratedSecurity = True}
Dim projectsUsers As New Dictionary(Of String, List(Of String))
Using sqlConn As New SqlConnection(csb.ConnectionString)
Dim sql = "SELECT [project], [user] FROM ProjectUser"
Using sqlCmd As New SqlCommand(sql, sqlConn)
sqlConn.Open()
Using rdr = sqlCmd.ExecuteReader()
If rdr.HasRows Then
While rdr.Read()
Dim project = rdr.GetString(0)
Dim user = rdr.GetString(1)
If projectsUsers.ContainsKey(project) Then
projectsUsers(project).Add(user)
Else
projectsUsers.Add(project, New List(Of String) From {user})
End If
End While
End If
End Using
End Using
End Using
' adjust output as required
For Each kvp In projectsUsers
Console.WriteLine(kvp.Key amp; ": " amp; String.Join(", ", kvp.Value))
Next
Console.ReadLine()
End Sub
End Module
и получил этот вывод:
SQL: Майкл, Сэм, Марк
C #: Сэм, Марк
Joomla: Марк
Вам просто нужно изменить метод для отображения выходных данных по желанию.
Комментарии:
1. Спасибо, Эндрю, я вижу, вы используете VB.net чтобы получить результат, то, что я ищу, чтобы сделать это с помощью SQL-запроса, чтобы загрузить его в datatable, а затем добавить этот datatable в datagridview, мне легко это сделать, но я просто хочу знать, может ли это быть прямым в sql какзапрос?
2. @michaelraouf Пожалуйста, отредактируйте свой вопрос, чтобы задать то, что вы на самом деле хотите спросить.