Извлечь> 901 строки из связанного сервера SQL Server 2008 в Active Directory - PullRequest
6 голосов
/ 14 апреля 2011

В SQL Server 2008 (версия 10.0.4000) я создал связанный сервер с сервером Active Directory.

Этот запрос:

select  TOP 901 *
from  openquery(adsisca, '
select  givenName,
                sn,
                sAMAccountName          
from    ''LDAP://10.1.2.3:389''
where   objectCategory = ''Person''
        and
        objectClass = ''InetOrgPerson''
')

работает.

Однако изменение запроса и попытка получить 902 строки не приводит:

select  TOP 902 *
    from  openquery(adsisca, '
    select  givenName,
                    sn,
                    sAMAccountName          
    from    ''LDAP://10.1.2.3:389''
    where   objectCategory = ''Person''
            and
            objectClass = ''InetOrgPerson''
    ')

Ошибка:

Сообщение 7330, Уровень 16, Состояние 2, Строка 1 Не удается получить aстрока от поставщика OLE DB "ADSDSOObject" для связанного сервера "adsisca".

Я обнаружил другие случаи, когда люди обсуждали ту же проблему на форумах, и они никогда не исправляли ее, просто обходили ее, записывая нескольконапример, просмотры и объединение их.

Есть ли более элегантное исправление, есть ли настройка, которую я могу изменить где-нибудь, чтобы получить более 901 строки?

Ответы [ 9 ]

7 голосов
/ 13 декабря 2013

Используйте объединение, чтобы обойти ограничение.

как это:

select  TOP 901 *
from  openquery(adsisca, '
select  givenName,
                sn,
                sAMAccountName          
from    ''LDAP://10.1.2.3:389''
where   objectCategory = ''Person''
        and
        objectClass = ''InetOrgPerson''
        and
        sAMAccountName < ''m''
')
union
select  TOP 901 *
from  openquery(adsisca, '
select  givenName,
                sn,
                sAMAccountName          
from    ''LDAP://10.1.2.3:389''
where   objectCategory = ''Person''
        and
        objectClass = ''InetOrgPerson''
        and
        sAMAccountName >= ''m''
')
4 голосов
/ 10 сентября 2013

Я знаю, что это старый пост, но у меня тоже были те же проблемы, и я рассмотрел предложенное решение выше.(В основном, используя несколько меньших выборок с изменяющимися критериями, чтобы уменьшить счетчик строк) Я просто вырезал немного другую версию и объединил их в Db View.Я не мог быть обеспокоен этой вещью MaxPageSize - это выглядит слишком много усилий.

IF NOT EXISTS(SELECT 1 FROM sys.servers WHERE name = 'ADSI') 
    EXEC sp_addlinkedserver 'ADSI', 'Active Directory Services 2.5', 'ADSDSOObject', 'adsdatasource'

-- Create a database view from unions of smaller selects. The max 901 records thing in AD forces us to do this.
DECLARE @queryFormat VARCHAR(MAX) = '
SELECT * FROM OPENQUERY(ADSI, ''
    SELECT userPrincipalName, samAccountName, telephoneNumber, mail, middleName, givenName, sn, displayName, distinguishedName
    FROM ''''LDAP://OU=Users, OU=ABC, DC=XYZ, DC=local''''
    WHERE objectClass = ''''User'''' AND objectCategory = ''''Person'''' AND samAccountName = ''''#p0'''''')';

DECLARE @sql VARCHAR(MAX) = 'CREATE VIEW [AdView] AS ';
DECLARE @asciiValue INT = ASCII('A');
DECLARE @asciiEnd INT = ASCII('Z');
WHILE @asciiValue <= @asciiEnd BEGIN 
    SET @sql = @sql + replace(@queryFormat, '#p0', CHAR(@asciiValue) + '*');
    IF @asciiValue < @asciiEnd  SET @sql = @sql + ' UNION ALL ';
    SET @asciiValue = @asciiValue + 1;
END
--PRINT @sql;

-- the 'live' view of the active directory data.
IF OBJECT_ID('[AdView]') IS NOT NULL DROP VIEW [AdView]
EXEC(@sql);

-- a 'snapshot' of the active directory data, for faster selects. you could execute this on a schedule to keep up to date.
IF OBJECT_ID('[AdTable]', 'U') IS NOT NULL DROP TABLE [AdTable]
SELECT * INTO [AdTable] FROM [AdView]
2 голосов
/ 28 марта 2017

Мне не очень понравился запах других опций, размещенных здесь, потому что с большим доменом очень возможно иметь более 901 учетных записей, начинающихся с одной и той же первой буквы - особенно если вы просматриваете учетные записи компьютеров, которые, вероятно, следуйте некоторому систематическому соглашению об именах, используя одну и ту же первую букву ...

Я немного поэкспериментировал и обнаружил, что если вы заказываете openquery с помощью uSNCreated и добавляете предложение TOP 901 во внешний запрос, он не взрывается.

Итак, вот мой SQL, который извлекает ВСЕ объекты активного каталога (компьютеры, контроллеры домена, пользователи и контакты) во временную таблицу в виде фрагментов из 901 записи и дает вам некоторую полезную информацию о каждом объекте.

CREATE TABLE #ADData(
    Login           NVARCHAR(256)
    ,CommonName     NVARCHAR(256)
    ,GivenName      NVARCHAR(256)
    ,FamilyName     NVARCHAR(256)   
    ,DisplayName    NVARCHAR(256)
    ,Title          NVARCHAR(256)
    ,Department     NVARCHAR(256)
    ,Location       NVARCHAR(256)
    ,Info           NVARCHAR(256)
    ,LastLogin      BIGINT
    ,flags          INT
    ,Email          NVARCHAR(256)
    ,Phone          NVARCHAR(256)   
    ,Mobile         NVARCHAR(256)
    ,Quickdial      NVARCHAR(256)
    , usnCreated    INT
)

DECLARE @Query      VARCHAR (2000)
DECLARE @Filter     VARCHAR(200)
DECLARE @Rowcount   INT

select @Filter =''

WHILE ISNULL(@rowcount,901)  = 901 BEGIN

    SELECT @Query = '
    SELECT top 901
            Login           = SamAccountName
            , CommonName    = cn
            , GivenName
            , FamilyName    = sn    
            , DisplayName
            , Title
            , Department
            , Location      = physicalDeliveryOfficeName
            , Info
            , LastLogin     = CAST(LastLogon AS bigint)
            , flags         = CAST (UserAccountControl as int)
            , Email         = mail
            , Phone         = telephoneNumber
            , Mobile        = mobile
            , QuickDial     = Pager
            , usnCreated
        FROM OPENROWSET(''ADSDSOObject'', '''', ''
                SELECT cn, givenName, sn, userAccountControl, lastLogon, displayName, samaccountname, 
                title,  department, physicalDeliveryOfficeName, info, mail, telephoneNumber, mobile, pager, usncreated
            FROM ''''LDAP://[ldap-query-string]'''' 
            WHERE objectClass=''''Person''''
            AND objectClass = ''''User''''
            ' + @filter + '
            ORDER BY usnCreated'')'             
    INSERT INTO #ADData EXEC (@Query) 
    SELECT @Rowcount = @@ROWCOUNT
    SELECT @Filter = 'and usnCreated > '+ LTRIM(STR((SELECT MAX(usnCreated) FROM #ADData)))

END

SELECT LOGIN            
        , CommonName    
        , GivenName
        , FamilyName
        , DisplayName
        , Title         
        , Department
        , Location      
        , Email         
        , Phone         
        , QuickDial     
        , Mobile        
        , Info          
        , Disabled      = CASE WHEN CAST (flags AS INT) & 2 > 0 THEN 'Y' ELSE NULL END 
        , Locked        = CASE WHEN CAST (flags AS INT) & 16  > 0 THEN 'Y' ELSE NULL END 
        , NoPwdExpiry   = CASE WHEN CAST (flags AS INT) & 65536  > 0 THEN 'Y' ELSE NULL END 
        , LastLogin     = CASE WHEN ISNULL(CAST (LastLogin AS BIGINT),0) = 0 THEN NULL ELSE 
                            DATEADD(ms, (CAST (LastLogin AS BIGINT) / CAST(10000 AS BIGINT)) % 86400000,
                            DATEADD(day, CAST (LastLogin AS BIGINT) / CAST(864000000000 AS BIGINT) - 109207, 0)) END 
        , Type = CASE WHEN flags  & 512 = 512 THEN 'user' 
                    WHEN flags IS NULL THEN 'contact' 
                    WHEN flags & 4096 = 4096 THEN 'computer'
                    WHEN flags & 532480 = 532480 THEN 'computer (DC)' END
FROM #ADData
ORDER BY Login

DROP TABLE #ADData
2 голосов
/ 23 апреля 2013

Проблема

Ошибка:

Сообщение 7330, уровень 16, состояние 2, строка 1 Не удается получить строку от поставщика OLE DB "ADSDSOObject" для связанного сервера "adsisca".

Я нашел другие случаи, когда люди обсуждали одну и ту же проблему на форумах, и они никогда не исправляли ее,> просто обходили ее, создавая несколько представлений и объединяя их, например.

Есть ли более элегантное исправление, есть ли настройка, которую я могу где-то изменить, чтобы получить более 901> строк?

Решение

Я только что решил ту же проблему, с которой столкнулся, без каких-либо изменений настроек Active Directory (и я успешно могу получить около 50 тыс. Логинов из AD, и не исключено, что я могу получить одну учетную запись входа из доменов AD ):

Необходимо обойти ограничение запросов ADSI, просматривая символы атрибутов. Смотрите решение здесь: http://www.sqlservercentral.com/Forums/Topic231658-54-1.aspx#bm1249991

Ошибка была устранена путем написания SELECT TOP 901 ... В МЕСТО ТОЛЬКО SELECT.

Эта проблема возникла у меня после переноса базы данных с 2005 на 2008, потому что в SQL Server 2008 существует ограничение в 901 рядов, которое было 1000 в SQL Server 2005 (разница в том, что нам нужно написать select TOP 901, который не требовался в SQL Server 2005, иначе программа завершается с ошибкой)

1 голос
/ 27 апреля 2011

Вам необходимо изменить параметр MaxPageSize в Active Directory.Для этого вам нужно использовать Ntdsutil.exe, который можно ввести в команду запуска, затем выполните следующие действия

  1. В командной строке Ntdsutil.exe введите LDAP policies и нажмите клавишу ВВОД.
  2. В командной строке политики LDAP введите Set MaxPageSize to 2000.-> Или любой номер, который вы хотите
  3. Чтобы просмотреть изменения, введите Show Values
  4. Чтобы сохранить изменения, введите Commit Changes
  5. Чтобы выйти, введите q
0 голосов
/ 09 октября 2017

Я так высоко оценил ответ Джона Синклера, что выбрал высшую форму лести - имитацию.Вот мое исполнение его решения.Вместо того чтобы объявлять соединение ADSI LDAP с каждым запросом в OpenRowSet, я выбрал метод OpenQuery:

DECLARE @DomainFQDN VARCHAR(50) = '<your.domain.FQDN>';

IF OBJECT_ID('tempdb..#ADData') IS NOT NULL
  DROP TABLE #ADData;

-- Query AD for all known user accounts
CREATE TABLE #ADData(
    lanId               NVARCHAR(256),
    firstName           NVARCHAR(256),
    lastName            NVARCHAR(256),
    email               NVARCHAR(256),
    costcenter          NVARCHAR(256),  --Our AD implementation uses the optional extensionAttributes, defining 1 as cost center
    mobile              NVARCHAR(256),  --In @Query below, the name of this column is the same as the LDAP returned parameter, so no equate is applied in the query
    country             NVARCHAR(256),
    usnCreated          BIGINT         --uSNCreated is an INT64 object type
);

--Define the AD LDAP connection
IF NOT EXISTS(SELECT 1 FROM sys.servers WHERE name = 'ADSI') 
 EXEC master.dbo.sp_addlinkedserver
    @server = N'ADSI', 
    @srvproduct = N'Active Directory Services',
    @provider = N'ADsDSOObject', 
    @datasrc = @DomainFQDN;

DECLARE @Rowcount int;
DECLARE @LastCreatedFilter VARCHAR(200) = '';
DECLARE @ADrecordsToReturn smallint = 901;  --AD will not return more than 901 records per query (changed from 1000 at some point). You can set it to any value smaller to control the 'pagesize' of returned results

--Loop mechanics:
-- - 1st loop: @Rowcount will be NULL but we need to looping to commence, thus ISNULL function
-- - Intermediate loops: Rowcount will equal the max number of requested records, indicating there may be more to query from AD
--SELECT @LastCreatedFilter = 'AND usnCreated = ''''<yourvalue>'''''; --Used during debugging to iniate the loop at a certain value
--DECLARE @TestStop int = 1;  -- @TestStop is a debug option to halt processing. It needs to be commented in or out at 3 places
WHILE ISNULL(@Rowcount,@ADrecordsToReturn) = @ADrecordsToReturn --AND @TestStop < 4  --Un-comment the three @TestStop lines to run a reduced sample query of AD, dictated by the value provided on this line (# of loops to process before stopping)
 BEGIN

    DECLARE @Query VARCHAR (2000) = 
     '
        SELECT TOP ' + CONVERT(varchar(10),@ADrecordsToReturn) + '
            lanId               = SamAccountName,
            firstName           = GivenName,
            lastName            = sn,
            email               = mail,
            bsbcc               = extensionAttribute1,
            mobile,
            country             = c,
            usnCreated
         FROM OpenQuery
          (
            ADSI,
            ''
                SELECT SamAccountName, GivenName, sn, mail, extensionAttribute1, mobile, c, usnCreated
                 FROM ''''LDAP://' + @DomainFQDN + '''''
                 WHERE objectCategory = ''''Person''''
                 AND objectClass = ''''user''''
                 ' + @LastCreatedFilter + '
                 ORDER BY usnCreated
            ''
          )
     ';  
    INSERT INTO #ADData EXEC (@Query);
    SELECT @Rowcount = @@ROWCOUNT;
    SELECT @LastCreatedFilter = 'AND usnCreated > ' + LTRIM(STR((SELECT MAX(usnCreated) FROM #ADData)));
--PRINT @LastCreatedFilter;  --While debugging, used to determine progress
--SET @TestStop = @TestStop + 1;  -- @TestStop is a debug option to halt processing. It needs to be commented in or out at 3 places
 END;

EXEC master.dbo.sp_dropserver 'ADSI';

--Do something with the results...
SELECT lanId, email, costcenter, mobile, country, usnCreated FROM #ADData order by lanId;
0 голосов
/ 13 июня 2017

Мне нравится вариант объединения, самый лучший и простой.

выберите TOP 901 * из открытого запроса (adsisca, 'выберите имя, sn, sAMAccountName
из' 'LDAP: //10.1.2.3: 389' ', где objectCategory =' 'Person' 'и objectClass ='' InetOrgPerson '' и sAMAccountName <'' m '' ') union выбирают TOP 901 * из openquery (adsisca,' select selectedName, sn, sAMAccountName <br>из '' LDAP: //10.1.2.3: 389 '' гдеobjectCategory = '' Person '' и objectClass = '' InetOrgPerson '' и sAMAccountName> = '' m '' ')

0 голосов
/ 01 мая 2015

Эта версия решения имеет дело с ситуациями, когда число пользователей, начинающихся с указанного символа, все еще> 901. Она использует основную процедуру, вызывающую другую хранимую процедуру.

-- This procedure pulls a subset of LDAP users

CREATE PROC [dbo].[Select_LDAP_Rows]
(
    @MyChar CHAR(1)
)
AS
BEGIN

--DECLARE @MyChar CHAR(1) = 'A';

DECLARE @queryFormat VARCHAR(MAX) = '
    SELECT * FROM OPENQUERY(ADSI, ''
        SELECT displayName, telephoneNumber, mail, mobile, facsimileTelephoneNumber
        FROM ''''LDAP://OU=PHC,dc=MyCompany,dc=org''''
        WHERE objectClass = ''''User'''' AND objectCategory = ''''Person'''' AND displayName = ''''' + @MyChar + '#p0'''''')
    ';

DECLARE @sql VARCHAR(MAX) = 'CREATE VIEW [AdView] AS ';
DECLARE @asciiValue INT = ASCII('A');
DECLARE @asciiEnd INT = ASCII('Z');

WHILE @asciiValue <= @asciiEnd BEGIN 
    SET @sql = @sql + replace(@queryFormat, '#p0', CHAR(@asciiValue) + '*');
    IF @asciiValue < @asciiEnd  SET @sql = @sql + ' UNION ALL ';
    SET @asciiValue = @asciiValue + 1;
END

--PRINT @sql;

-- the 'live' view of the active directory data.
IF OBJECT_ID('v_ADView') IS NOT NULL DROP VIEW v_ADView

EXEC(@sql);

-- ADTable holds a 'snapshot' of the active directory data.
IF OBJECT_ID('[Users_AD]', 'U') IS NULL
    SELECT DisplayName, TelephoneNumber AS Phone, Mail, Mobile, FacsimileTelephoneNumber AS Fax 
    INTO [Users_AD] FROM v_ADView;
ELSE
    INSERT INTO [Users_AD] 
    SELECT DisplayName, TelephoneNumber AS Phone, Mail, Mobile, FacsimileTelephoneNumber AS Fax 
    FROM v_ADView;

END


GO


-- By calling Select_LDAP_Rows with a separate character each time,
-- build up a table containing all the LDAP data for each user.

ALTER PROC [dbo].[Select_LDAP_Rows_Master]
AS

BEGIN

-- ADTable holds a 'snapshot' of the active directory data.
IF OBJECT_ID('[AdTable]', 'U') IS NOT NULL DROP TABLE [AdTable];

-- Create a database view from unions of smaller selects. The max 901 records thing in AD forces us to do this.

DECLARE @sql VARCHAR(200)
DECLARE @asciiValue INT = ASCII('A');
DECLARE @asciiEnd INT = ASCII('Z');

-- Create a view of the active directory data and insert to table Users_AD
WHILE @asciiValue <= @asciiEnd BEGIN 

    SET @sql = 'EXEC dbo.Select_LDAP_Rows ' + CHAR(@asciiValue) + ' ';
    SET @asciiValue = @asciiValue + 1;

    --PRINT @sql;

    EXEC(@sql);

END

END
0 голосов
/ 26 апреля 2014

Мне нужно изменить параметр MaxTempTableSize в Active Directory.Для этого вам нужно использовать Ntdsutil.exe, который вы можете ввести в команду запуска, а затем выполните следующие действия

At the Ntdsutil.exe command prompt, type LDAP policies, and then press ENTER.
At the LDAP policy command prompt, type Set MaxTempTableSize to 2000. -> Or any number you want
To view the changes, type Show Values
To save the changes, typeCommit Changes
To quit, type q
...