Как выглядит SharePoint со стороны БД? Ну как то так..
Для человека который первый раз залез под капот тут не все так очевидно как хотелось бы, поэтому попробуем немного разобраться в этом вопросе.
Предупреждение: Любые изменения в SharePoint через СУБД могут нарушить структуру базы и привести к тому что ваш SharePoint перестанет работать.
Все операции выполняются на свой страх и риск, поэтому перед тем как выполнять в боевой базе необходимо детально проверить скрипты на тестовой.
Если немного приглядеться можно выделить основные таблицы SharePoint и связи между ними
AllLists
| |
ОСНОВНАЯ таблица содержит мета информацию о каждом элементе в списке.
| |
Содержит информацию обо всех документах (и всех элементах списка) для каждой библиотеки и списка.
| |
DocStreams
|
Содержит сами документы в BLOB поле Content varbinary (max).
|
NameValuePair
|
Индексируемые поля для списков.
|
AllUserDataJunctions
|
Содержит множественный выбор значений полей.
|
ContentTypes
|
Содержит описание используемых типов
|
Features
|
Содержит информацию об активированных дополнениях для каждой коллекции сайтов или сайта.
|
Содержит информацию о всех коллекциях сайтов в базе.
| |
Содержит информацию о сайтах (webs) в каждой коллекции сайта.
| |
Содержит информацию о пользователях.
| |
Groups
|
Содержит информацию о группах пользователей в каждой коллекции сайтов.
|
Roles
|
Содержит роли (уровни доступа) для каждого сайта.
|
Содержит информацию о членах групп.
| |
RoleAssignment
|
Содержит информацию обо всех пользователях или группах SharePoint которые присвоены ролям.
|
SchedSubscriptions
|
Содержит информацию обо всех настроенных подписках по расписанию
|
ImmedSubscriptions
|
Таблица содержащая информацию обо всех непосредственных подписках.
|
1. Информацию о списках Sharepoint можно получить из таблицы AllLists
SELECT
List.tp_SiteId,
List.tp_WebId,
List.tp_ID , --идентификатор списка
tp_BaseType , --тип списка: Generic List: 0, Document Library: 1, Discussion Board:3, Survey:4,Issue:5
tp_ServerTemplate, --ex:100-Generic list,101-Document library,102-Survey,103-Links list,104-Announcements list,105-Contacts list,106-Events list, 107-Tasks list,108-Discussion board,109-Picture library
list.tp_Title , --название списка
list.tp_Fields , --описание полей в библиотеке
list.tp_ContentTypes --описание типов в библиотеке
FROM alllists LIST WHERE lower(LIST.tp_Title) LIKE N'%входящие%2011%' and (list.[tp_DeleteTransactionId] = 0x )
Поля tp_Fields, tp_ContentTypes хранятся в сжатом двоичном виде, чтобы распаковать их достаточно использовать функцию ниже
private static string getXmlFromTpFields(byte[] tpFields)
{
using (var memoryStream = new MemoryStream(tpFields))
{
// пропускаем первые 14 байтов
for (var index = 0; index <= 13; index++)
memoryStream.ReadByte();
var deflateStream = new DeflateStream(memoryStream, CompressionMode.Decompress);
using (var destination = new MemoryStream())
{
deflateStream.CopyTo(destination);
var streamReader = new StreamReader(destination);
destination.Position = 0;
return streamReader.ReadToEnd();
}
}
}
2. Где хранится вся инфа ? Ответ прост в AllUserData
Для элементов ведется история изменений,поэтому нужно правильно определять версию с которой необходимо работать по полю
[tp_IsCurrentVersion] = CONVERT(bit,1) и тип контента по полю tp_ContentTypeId
tp_ID[int]
|
Идентификатор записи
|
tp_GUID[uniqueidentifier]
|
GUID записи
|
tp_ListId [uniqueidentifier]
|
GUID списка. Содержится в поле 'tp_ID' в таблице 'AllLists'
|
tp_SiteId [uniqueidentifier]
|
GUID сайта. Содержится в поле 'Id' в таблице 'AllSites'
|
tp_RowOrdinal [tinyint]
|
индекс строки в элементе, начинается с 0
|
tp_ContentTypeID
|
Тип элемента, унаследованный. Содержится в таблице ContentType.
|
tp_Author [int]
|
Пользователь создавший элемент
|
tp_Editor [int]
|
Последний пользователь редактировавший запись
|
tp_Modified [datetime]
|
Время изменения записи
|
tp_Created [datetime]
|
Время создания записи
|
tp_DeleteTransactionId [varbinary]
|
Удаленные элементы в корзине. Для не удалённых элементов содержит 0x
|
tp_IsCurrentVersion [bit]
|
Значение отражает текущую версию записи, для среди истории изменений. Для текущей версии элемента содержит значение 1
|
nvarchar1..64 [nvarchar]
|
Столбцы navarchar1,navarchar2….navarchar64 stores хранят в себе значения типа nvarchar, всего 64 поля, если не столбец не содержит значение тогда NULL
|
ntext1..32 [ntext]
|
Столбцы ntext1 to ntext32 stores хранят в себе значения типа ntext, всего 32 поля, если не столбец не содержит значение тогда NULL
|
bit1..16[bit]
|
хранят в себе значения типа bit, всего 16 полей, если не столбец не содержит значение тогда NULL
|
datetime1..8 [datetime]
|
хранят в себе значения типа datetime, всего 8 полей, если не столбец не содержит значение тогда NULL
|
float1..12 [float]
|
хранят в себе значения типа float, всего 12 полей, если не столбец не содержит значение тогда NULL
|
int1..16 [int]
|
хранят в себе значения типа int, всего 16 полей, если не столбец не содержит значение тогда NULL
|
sql_variant1..8 [sql_variant]
|
хранят в себе значения типа sql_variant, всего 8 полей, если не столбец не содержит значение тогда NULL
|
Простой запрос выглядит так по все элементам которые не удалены и не в корзине и последняя версия
SELECT top 100 DAT.*
FROM [WSS_Content_RBS].dbo.[AllUserData] DAT (nolock)
INNER JOIN [WSS_Content_RBS].dbo.alllists LIST (nolock) ON LIST.tp_ID = DAT.tp_ListId and LIST.tp_SiteId = DAT.tp_SiteId
AND LIST.tp_SiteId = 'CB5AF988-C67A-4605-91EB-68F846A1D596'
AND lower(LIST.tp_Title) LIKE N'%входящие%[0-9]%'
WHERE cast(DAT.tp_ContentTypeId as binary(19)) = 0x0120D5200055418DF2944E344D9BB430577FCA –нужный тип элемента
and DAT.[tp_IsCurrentVersion] = CONVERT(bit,1) --текущая версия
and DAT.[tp_DeleteTransactionId] = 0x -- не в корзине
and DAT.[tp_RowOrdinal] = 0 -- индекс строки, документ может состоять из нескольких строк
and DAT.[tp_CalculatedVersion] = 0 --0 если версия текущая
Столбец tp_Columnset [XML] COLUMN_SET FOR ALL_SPARSE_COLUMNS NULL
XML представление всех заполненных разреженных SPARSE столбцов в таблице AllUserdata,
по аналогии с вычисляемыми столбцами физически не хранится в базе, отличается от вычисляемого тем что можно изменять напрямую через UPDATE
SPARSE столбцы это обычные столбцы оптимизированные для хранения пустых значений.
3. Таблица Content Type , SharePoint Content Type ID GUID's
Данные в таблице AllUserData разделяются по типам, типы хранятся в двоичном виде и создаются наследованием от родительского типа.
Наследование выполняется в виде связи строк с разделителем '00′. Форма записи выглядит так '0x[baseID]00[GUID (new id)]00[и так далее]'.
В качестве примера наследовать будем от базового типа 0×01. Наследуемый тип будет выглядеть например так 0×010100E0D3BD7003DA22419C52027ABF151.
Созданный новый тип будет начинаться с элемента (0×01) затем идет разделитель '00′ и GUID присвоенный новому типу.
Чтобы найти родительский тип достаточно разделить строку по разделителю '00′ и пройти по цепочке наследования.
Полезные запросы:
--найти нужный тип
SELECT * FROM [dbo].[ContentTypes] t WHERE lower(t.resourcedir) like N'%набор%'
--выбрать элементы по типу
SELECT TOP 100 * FROM AllUserData AS aud WHERE cast(aud.tp_ContentTypeId as binary(19)) = 0x010100A71AE871CC36F34AB8F57FA290225A27
-- найти доччерние типы и в каких списках используется
DECLARE @SiteId UNIQUEIDENTIFIER, @Class BIT, @ContentTypeId tContentTypeId, @IsFieldId bit
--настраиваем параметры
SELECT @SiteId = 'CB5AF988-C67A-4605-91EB-68F846A1D596' , @Class = 1 /* Needs always 1 means is a ContentType */ , @ContentTypeId = 0x0120D520 , @IsFieldId = 0
--найти все дочерние ContentTypeId
select ContentTypeId,Scope,[Version],ResourceDir,SolutionId,IsFromFeature
from ContentTypes WITH (INDEX=ContentTypes_SiteClassCTId, FORCESEEK)
where SiteId = @SiteId AND Class = @Class AND
ContentTypeId <= (@ContentTypeId + 0xFF) AND ContentTypeId > @ContentTypeId
--в каком списке используется этот ContentTypeId
select W.FullUrl as Url ,L.tp_Title as ListTitle
from ContentTypeUsage WITH (INDEX=ContentTypeUsage_SiteIsFClassCTIdWeb, FORCESEEK)
Join Lists L on L.tp_ID = ContentTypeUsage.ListId
Join Webs W on W.Id = ContentTypeUsage.WebId
Where ContentTypeUsage.SiteId = @SiteId AND ((@IsFieldId IS NULL AND IsFieldId IS NULL) OR @IsFieldId=IsFieldId) AND
Class = @Class AND
ContentTypeId <= (@ContentTypeId + 0xFF) AND
ContentTypeId >= @ContentTypeId
Также можно узнать типы через PowerShell, следующим скриптом
|
Ниже результат работы скрипта
Проиндексировав столбец в Sharepoint можно легко увидеть как заполняется таблица NameValuePair[_{SQLCollation}] индексируемыми полями. Давайте взглянем на схему таблицы.
SiteId: GUID сайта
WebId: GUID подсайта
ListId: GUID листа
ItemId: Идентификатор tp_id из AllUserData
Level: уровень элемента
FieldId: GUID поля
Value: Значение столбца
Что важно знать, каждое значение индексируемого поля хранится этой таблице и должно быть обновлено вместе с таблицей AllUserdata.
На каждое индексируемое поле создается одна запись если 3 поля индексируются создается 3 записи и тд
Так можно посмотреть список проиндексированных столбцов
SELECT al.tp_Title , nvp.FieldId , COUNT(*)
FROM NameValuePair AS nvp INNER JOIN alllists al ON nvp.SiteId = al.tp_SiteId and nvp.WebId = al.tp_WebId AND nvp.ListId = al.tp_ID
GROUP BY al.tp_Title , nvp.FieldId
ORDER BY al.tp_Title
5. Где и как хранятся сами документы.
В таблице AllDocs хранятся описания связанных документов, сами документы хранятся в таблице
SELECT top 100 UserData.* , t1.* FROM AllUserData AS UserData
INNER LOOP JOIN AllDocs AS t1
ON (UserData.[tp_RowOrdinal] = 0 )
AND ( t1.SiteId=UserData.tp_SiteId )
AND (t1.SiteId = 'CB5AF988-C67A-4605-91EB-68F846A1D596' )
AND (t1.ParentId = UserData.tp_ParentId)
AND (t1.Id = UserData.tp_DocId)
AND ((UserData.tp_Level = 1 OR UserData.tp_Level =255 ) )
AND (t1.Level = UserData.tp_Level)
AND ( UserData.[tp_IsCurrentVersion] = CONVERT(bit, 1) )
AND (UserData.[tp_CalculatedVersion] = 0 )
AND (UserData.[tp_DeleteTransactionId] = 0x )
AND (t1.[DeleteTransactionId] = 0x )
В таблице DocStreams хранятся сами документы в двоичном виде в поле Content
SELECT * FROM DocStreams d
WHERE d.SiteId = 'CB5AF988-C67A-4605-91EB-68F846A1D596'
and d.DocId = 'C97A9C4C-E37B-492A-BD92-11A7290EE942' --Идентификатор документа tp_DocId из Alluserdata
Чтобы экспортировать документ в файл можно воспользоваться утилитой командной строки bcp, подробнее тут
bcp "SELECT Content FROM AllDocStreams WHERE ID = '05AE4037-782E-4BA6-A924-FA3EEDA0DCCE'"
queryout Sean_Excell_file.xlsx -S ServerName -T
-d My_Content_Database -f Path_To_Format_File.fmt
Если не получится можно скриптом ниже
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO
--Now that you have access to the file system you can run the following script. Extracting files from database:
--DECLARING THE CURSOR, THIS IS THE ITEMS YOU WANT TO RUN THE EXTRACTING ON
DECLARE CURSOR_Images CURSOR FOR (SELECT Id FROM [dbo].[AllDocs] t1 where t1.LeafName = 'TT499964.pdf')
--DECLARE THE TYPE OF THE COLUMN YOU SELECTED ABOVE
DECLARE @ImageID uniqueidentifier;
--START THE CURSOR AND RUN THROUGH ALL THE ITEMS IN CURSOR_Images
OPEN CURSOR_Images
FETCH NEXT FROM CURSOR_Images INTO @ImageID
WHILE (@@FETCH_STATUS <> -1)
BEGIN
--DECLARE THE VARIABLE THAT WILL KEEP THE BINARY DATA
DECLARE @ImageData varbinary(MAX);
--SELECT THE BINARY DATA AND SET IT TO @ImageData. THE BINARY DATA FOR ALLDOCS ARE LOCATED IN ALLDOCSTREAMS
--AND THE ID IS THE SAME AS IN ALLDOCS
SELECT @ImageData = (SELECT TOP 1 CONVERT(varbinary(MAX), Content, 1) FROM [dbo].[AllDocStreams] WHERE Id = @ImageID ORDER BY InternalVersion ASC);
--GET THE LOCATION OF THE DIRECTORY THE FILES WAS SAVED IN AND CHANGE REPLACE THE / WITH \ TO BE USED IN FILESYSTEM
DECLARE @DIRPATH NVARCHAR(MAX);
SET @DIRPATH = REPLACE((SELECT DirName FROM [dbo].[AllDocs] WHERE Id = @ImageID),'/','\');
--SET THE PATH
DECLARE @Path nvarchar(1024);
SELECT @Path = 'C:\Export\' + @DIRPATH + '\';
--CREATE THE DIRECTORIES
EXEC master.dbo.xp_create_subdir @Path;
--GET THE FILE NAME OF THE FILE FROM LEAFNAME
DECLARE @Filename NVARCHAR(1024);
SELECT @Filename = (SELECT LeafName FROM [dbo].[AllDocs] WHERE id = @ImageID);
--SET THE FULL PATH FOR WHERE THE FILES WILL BE STORED
DECLARE @FullPathToOutputFile NVARCHAR(2048);
SELECT @FullPathToOutputFile = @Path + '\' + @Filename;
--SAVE THE FILE TO THE FILE SYSTEM
DECLARE @ObjectToken INT
EXEC sp_OACreate 'ADODB.Stream', @ObjectToken OUTPUT;
EXEC sp_OASetProperty @ObjectToken, 'TYPE', 1;
EXEC sp_OAMethod @ObjectToken, 'OPEN';
EXEC sp_OAMethod @ObjectToken, 'WRITE', NULL, @ImageData;
EXEC sp_OAMethod @ObjectToken, 'SaveToFile', NULL, @FullPathToOutputFile, 2;
EXEC sp_OAMethod @ObjectToken, 'Close';
EXEC sp_OADestroy @ObjectToken;
--LOOP TO THE NEXT ENTRY IN THE CURSOR
FETCH NEXT FROM CURSOR_Images INTO @ImageID
END
CLOSE CURSOR_Images
DEALLOCATE CURSOR_Images
5. Запрос для представления в общем виде выглядит так
SELECT
DISTINCT t10.[tp_Ordinal],
t6.[tp_ID] AS c21,
t11.[nvarchar10] AS c21c18,
t9.*
FROM
(
SELECT
TOP(@NUMROWS)
*
FROM
--таблица индексируемых полей для списка
NameValuePair AS NVP
INNER LOOP JOIN
--основная запись по элементу списка
AllUserData AS UserData ON UserData... = NVP... -- (AND NVP.SiteId = @SITEID AND NVP.ListId = @LISTID AND NVP.FieldId = @L7)
--информация по документу
INNER LOOP JOIN AllDocs AS t1 ON t1... = UserData... --t1.Id = UserData.tp_DocId
--раскрываем значения полей
LEFT OUTER LOOP JOIN AllUserData AS t2 ON t2... = UserData... --UserData.[tp_CheckoutUserId]=t2.[tp_ID]
LEFT OUTER LOOP JOIN AllUserData AS t3 ON t3... = UserData... --UserData.[int2]=t3.[tp_ID]
LEFT OUTER LOOP JOIN AllUserData AS t4 ON t4... = UserData.. --UserData.[int8]=t4.[tp_ID]
LEFT OUTER LOOP JOIN AllUserData AS t5 ON t5... = UserData.. --UserData.[int6]=t5.[tp_ID]
LEFT OUTER LOOP JOIN AllUserData AS t7 ON t7... = UserData.. --UserData.[int7]=t7.[tp_ID]
LEFT OUTER LOOP JOIN AllUserData AS t8 ON t8... = UserData.. --UserData.[int13]=t8.[tp_ID]
WHERE
--фильтры по пользователям, спискам и тд
) AS t9
--раскрываем множественные значения для документа
LEFT OUTER JOIN AllUserDataJunctions AS t10 ON t10... = t9... -- t9.[tp_DocId] = t10.[tp_DocId]
LEFT OUTER JOIN AllUserDataJunctions AS t6 ON t6... = t9... AND (t10.[tp_Ordinal] = t6.[tp_Ordinal]) AND (t6.[tp_FieldId] = @L12)
--получаем названия для множественных значений
LEFT OUTER LOOP JOIN AllUserData AS t11 ON ... t11.[tp_Id] = t6.[tp_ID]
ORDER BY t9.tp_Modified ASC , t9.tp_ID ASC , t10.[tp_Ordinal] ASC
SELECT LIST.tp_ID , list.tp_Title FROM alllists LIST WHERE lower(LIST.tp_Title) LIKE N'%входящие%2011%'
И открыть страницу SharePoint с нужным списком, в профайлере получим требуемый динамический запрос exec sp_executesql, который при желании можно отформатировать и придать ему читабельный вид
5. Полезные запросы
1) Query to get all the top level site collections
SELECT SiteId AS SiteGuid, Id AS WebGuid, FullUrl AS Url, Title, Author, TimeCreated
FROM dbo.Webs
WHERE (ParentWebId IS NULL)
2) Query to get all the child sites in a site collection
SELECT SiteId AS SiteGuid, Id AS WebGuid, FullUrl AS Url, Title, Author, TimeCreated
FROM dbo.Webs
WHERE (NOT (ParentWebId IS NULL))
3) Query to get all the SharePoint groups in a site collection
SELECT dbo.Webs.SiteId, dbo.Webs.Id, dbo.Webs.FullUrl, dbo.Webs.Title, dbo.Groups.ID AS Expr1,
dbo.Groups.Title AS Expr2, dbo.Groups.Description
FROM dbo.Groups INNER JOIN
dbo.Webs ON dbo.Groups.SiteId = dbo.Webs.SiteId
4) Query to get all the users in a site collection
SELECT dbo.Webs.SiteId, dbo.Webs.Id, dbo.Webs.FullUrl, dbo.Webs.Title, dbo.UserInfo.tp_ID,
dbo.UserInfo.tp_DomainGroup, dbo.UserInfo.tp_SiteAdmin, dbo.UserInfo.tp_Title, dbo.UserInfo.tp_Email
FROM dbo.UserInfo INNER JOIN
dbo.Webs ON dbo.UserInfo.tp_SiteID = dbo.Webs.SiteId
5) Query to get all the members of the SharePoint Groups
(i) All the members in all the SharePoint Groups in a web application.
SELECT dbo.Groups.ID, dbo.Groups.Title, dbo.UserInfo.tp_Title, dbo.UserInfo.tp_Login
FROM dbo.GroupMembership INNER JOIN
dbo.Groups ON dbo.GroupMembership.SiteId = dbo.Groups.SiteId INNER JOIN
dbo.UserInfo ON dbo.GroupMembership.MemberId = dbo.UserInfo.tp_ID
(ii)All the members in each SharePoint Group in a web application.
SELECT dbo.Groups.ID, dbo.Groups.Title, dbo.UserInfo.tp_Title, dbo.UserInfo.tp_Login
FROM dbo.GroupMembership with (nolock)
INNER JOIN dbo.Groups with (nolock)
ON dbo.GroupMembership.GroupId = Groups.ID
INNER JOIN dbo.UserInfo
ON dbo.GroupMembership.MemberId = dbo.UserInfo.tp_ID
6) Query to get all the sites where a specific feature is activated
SELECT dbo.Webs.Id AS WebGuid, dbo.Webs.Title AS WebTitle, dbo.Webs.FullUrl AS WebUrl, dbo.Features.FeatureId,
dbo.Features.TimeActivated
FROM dbo.Features INNER JOIN
dbo.Webs ON dbo.Features.SiteId = dbo.Webs.SiteId AND dbo.Features.WebId = dbo.Webs.Id
WHERE (dbo.Features.FeatureId = '00DGEA71-E2FE-42de-9DF3-A44065BE0104')
7) Query to get all the users assigned to roles
SELECT dbo.Webs.Id, dbo.Webs.Title, dbo.Webs.FullUrl, dbo.Roles.RoleId, dbo.Roles.Title AS RoleTitle,
dbo.UserInfo.tp_Title, dbo.UserInfo.tp_Login
FROM dbo.RoleAssignment INNER JOIN
dbo.Roles ON dbo.RoleAssignment.SiteId = dbo.Roles.SiteId AND
dbo.RoleAssignment.RoleId = dbo.Roles.RoleId INNER JOIN
dbo.Webs ON dbo.Roles.SiteId = dbo.Webs.SiteId AND dbo.Roles.WebId = dbo.Webs.Id INNER JOIN
dbo.UserInfo ON dbo.RoleAssignment.PrincipalId = dbo.UserInfo.tp_ID
8) Query to get all the SharePoint groups assigned to roles
SELECT dbo.Webs.Id, dbo.Webs.Title, dbo.Webs.FullUrl, dbo.Roles.RoleId, dbo.Roles.Title AS RoleTitle,
dbo.Groups.Title AS GroupName
FROM dbo.RoleAssignment INNER JOIN
dbo.Roles ON dbo.RoleAssignment.SiteId = dbo.Roles.SiteId AND
dbo.RoleAssignment.RoleId = dbo.Roles.RoleId INNER JOIN
dbo.Webs ON dbo.Roles.SiteId = dbo.Webs.SiteId AND dbo.Roles.WebId = dbo.Webs.Id INNER JOIN
dbo.Groups ON dbo.RoleAssignment.SiteId = dbo.Groups.SiteId AND
dbo.RoleAssignment.PrincipalId = dbo.Groups.ID
SELECT SiteId AS SiteGuid, Id AS WebGuid, FullUrl AS Url, Title, Author, TimeCreated
FROM dbo.Webs
WHERE (ParentWebId IS NULL)
2) Query to get all the child sites in a site collection
SELECT SiteId AS SiteGuid, Id AS WebGuid, FullUrl AS Url, Title, Author, TimeCreated
FROM dbo.Webs
WHERE (NOT (ParentWebId IS NULL))
3) Query to get all the SharePoint groups in a site collection
SELECT dbo.Webs.SiteId, dbo.Webs.Id, dbo.Webs.FullUrl, dbo.Webs.Title, dbo.Groups.ID AS Expr1,
dbo.Groups.Title AS Expr2, dbo.Groups.Description
FROM dbo.Groups INNER JOIN
dbo.Webs ON dbo.Groups.SiteId = dbo.Webs.SiteId
4) Query to get all the users in a site collection
SELECT dbo.Webs.SiteId, dbo.Webs.Id, dbo.Webs.FullUrl, dbo.Webs.Title, dbo.UserInfo.tp_ID,
dbo.UserInfo.tp_DomainGroup, dbo.UserInfo.tp_SiteAdmin, dbo.UserInfo.tp_Title, dbo.UserInfo.tp_Email
FROM dbo.UserInfo INNER JOIN
dbo.Webs ON dbo.UserInfo.tp_SiteID = dbo.Webs.SiteId
5) Query to get all the members of the SharePoint Groups
(i) All the members in all the SharePoint Groups in a web application.
SELECT dbo.Groups.ID, dbo.Groups.Title, dbo.UserInfo.tp_Title, dbo.UserInfo.tp_Login
FROM dbo.GroupMembership INNER JOIN
dbo.Groups ON dbo.GroupMembership.SiteId = dbo.Groups.SiteId INNER JOIN
dbo.UserInfo ON dbo.GroupMembership.MemberId = dbo.UserInfo.tp_ID
(ii)All the members in each SharePoint Group in a web application.
SELECT dbo.Groups.ID, dbo.Groups.Title, dbo.UserInfo.tp_Title, dbo.UserInfo.tp_Login
FROM dbo.GroupMembership with (nolock)
INNER JOIN dbo.Groups with (nolock)
ON dbo.GroupMembership.GroupId = Groups.ID
INNER JOIN dbo.UserInfo
ON dbo.GroupMembership.MemberId = dbo.UserInfo.tp_ID
6) Query to get all the sites where a specific feature is activated
SELECT dbo.Webs.Id AS WebGuid, dbo.Webs.Title AS WebTitle, dbo.Webs.FullUrl AS WebUrl, dbo.Features.FeatureId,
dbo.Features.TimeActivated
FROM dbo.Features INNER JOIN
dbo.Webs ON dbo.Features.SiteId = dbo.Webs.SiteId AND dbo.Features.WebId = dbo.Webs.Id
WHERE (dbo.Features.FeatureId = '00DGEA71-E2FE-42de-9DF3-A44065BE0104')
7) Query to get all the users assigned to roles
SELECT dbo.Webs.Id, dbo.Webs.Title, dbo.Webs.FullUrl, dbo.Roles.RoleId, dbo.Roles.Title AS RoleTitle,
dbo.UserInfo.tp_Title, dbo.UserInfo.tp_Login
FROM dbo.RoleAssignment INNER JOIN
dbo.Roles ON dbo.RoleAssignment.SiteId = dbo.Roles.SiteId AND
dbo.RoleAssignment.RoleId = dbo.Roles.RoleId INNER JOIN
dbo.Webs ON dbo.Roles.SiteId = dbo.Webs.SiteId AND dbo.Roles.WebId = dbo.Webs.Id INNER JOIN
dbo.UserInfo ON dbo.RoleAssignment.PrincipalId = dbo.UserInfo.tp_ID
8) Query to get all the SharePoint groups assigned to roles
SELECT dbo.Webs.Id, dbo.Webs.Title, dbo.Webs.FullUrl, dbo.Roles.RoleId, dbo.Roles.Title AS RoleTitle,
dbo.Groups.Title AS GroupName
FROM dbo.RoleAssignment INNER JOIN
dbo.Roles ON dbo.RoleAssignment.SiteId = dbo.Roles.SiteId AND
dbo.RoleAssignment.RoleId = dbo.Roles.RoleId INNER JOIN
dbo.Webs ON dbo.Roles.SiteId = dbo.Webs.SiteId AND dbo.Roles.WebId = dbo.Webs.Id INNER JOIN
dbo.Groups ON dbo.RoleAssignment.SiteId = dbo.Groups.SiteId AND
dbo.RoleAssignment.PrincipalId = dbo.Groups.ID
9)количество
используемых терминов
SELECT
g.Name AS
GroupName ,s.Name TermSetName, m.[TermSetId] , s.UniqueId,
COUNT( DISTINCT m.[TermId]) CNT
FROM
[dbo].[ECMUsedTerms] m
LEFT
JOIN [dbo].[ECMTerm] t ON t.Id = m.TermId AND t.PartitionId = m.PartitionId
LEFT
JOIN [dbo].[ECMTermSet] s (NOLOCK) ON s.UniqueId = m.TermSetId and m.PartitionId = s.PartitionId
LEFT
OUTER JOIN dbo.ECMGroup g (NOLOCK) ON g.Id = s.GroupId AND g.PartitionId = s.PartitionId
WHERE
t.IsDeleted = 0 AND t.MergedIdList IS NULL
GROUP
BY g.Name, s.Name , m.[TermSetId] , s.UniqueId
P.S: Для изучения структуры SharePoint очень пригодится утилита SharePoint Manager
После запуска приложение автоматически найдет локальную ферму и подключится к ней.
Программа позволяет просматривать каждый сайт вашей локальной фермы и все свойства объектов. Также можно изменять значения некоторых свойств. Важно, что все сделанные изменения приступают в силу после нажатия на кнопку Сохранить.
Кроме просмотра и изменения свойств для некоторых типов объектов (поля, типы контента и т.д.) можно посмотреть их схему (рис. 2)
Также можно активировать и деактивировать возможности (Features).
Еще один способ применения – понимание структуры фермы SharePoint.
К недостаткам можно отнести отсутствие возможности подключения к удаленной ферме.