如何解决从SQL Server 2008链接服务器中检索> 901行到Active Directory
|| 在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,sAMAccountName
from \'\'LDAP://10.1.2.3:389\'\'
where objectCategory = \'\'Person\'\'
and
objectClass = \'\'InetOrgPerson\'\'
\')
错误是:
Msg 7330,第16级,州2,第1行
无法从OLE DB获取行
提供程序\“ ADSDSOObject \”用于链接
服务器\“ adsisca \”。
我发现其他人在论坛上讨论相同的问题,但他们从未解决过,只是围绕它编写了多个视图并将它们合并在一起。
是否有更优雅的解决方案,是否可以更改某个地方以检索901行以上的设置?
解决方法
使用联合来规避限制..
像这样 :
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,sAMAccountName
from \'\'LDAP://10.1.2.3:389\'\'
where objectCategory = \'\'Person\'\'
and
objectClass = \'\'InetOrgPerson\'\'
and
sAMAccountName >= \'\'m\'\'
\')
,我知道这是一个旧帖子,但是我也遇到了同样的问题,并检查了上面提出的解决方案。 (基本上是使用一堆较小的选择以及不断变化的条件来减少行数),我只是剪切了一个略有不同的版本,并将它们全部合并为Db视图。我不能为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,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]
,问题
错误是:
消息7330,级别16,状态2,第1行无法从OLE DB提供程序“ ADSDSOObject”获取链接服务器“ adsisca”的行。
我发现其他人在论坛上讨论相同的问题,但是他们从未解决过,只是解决了问题,例如编写了多个视图并将它们合并在一起。
是否有更优雅的解决方案,是否可以更改某个地方以获取901>行以上的设置?
解决方案
我只是解决了我面临的相同问题,而无需进行任何Active Directory设置更改(并且我能够成功地从AD检索大约5万次登录,并且从AD域中获取一个登录帐户也不失踪):
您需要通过遍历属性的字符来解决ADSI查询限制。在此处查看解决方案:http://www.sqlservercentral.com/Forums/Topic231658-54-1.aspx#bm1249991
通过在仅ѭ5的地方写入SELECT TOP 901 ...
解决了错误。
从2005年到2008年数据库迁移后,我遇到了这个问题,因为在SQL Server 2008中,限制为901行,而在SQL Server 2005中限制为1000行(不同之处是我们需要编写select TOP 901,而不是SQL Server 2005中必需的,否则程序将失败并显示错误)
,我不太喜欢这里发布的其他选项的味道,因为对于大型域,很有可能拥有多个以相同的首字母开头的901个帐户-特别是如果您正在查看的计算机帐户,则可能会跟随一些使用相同的首字母的系统命名约定...
我进行了一些尝试,发现如果您通过uSNCreated订购openquery并在外部查询上放置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,userAccountControl,lastLogon,samaccountname,title,department,physicalDeliveryOfficeName,info,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,FamilyName,Location,Email,Phone,QuickDial,Mobile,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
,您需要在Active Directory中更改MaxPageSize设置。为此,您需要使用Ntdsutil.exe,您可以在run命令上键入它,然后按照以下步骤操作
在Ntdsutil.exe命令提示符下,键入7,然后按Enter。
在LDAP策略命令提示符下,键入Set MaxPageSize to 2000
。 ->或您想要的任何数字
要查看更改,请键入Show Values
要保存更改,请键入Commit Changes
要退出,请输入q
,我需要在Active Directory中更改MaxTempTableSize设置。为此,您需要使用Ntdsutil.exe,您可以在run命令上键入它,然后按照以下步骤操作
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
,此版本的解决方案处理的情况是,以指定字符开头的用户数量仍大于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,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,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,FacsimileTelephoneNumber AS Fax
INTO [Users_AD] FROM v_ADView;
ELSE
INSERT INTO [Users_AD]
SELECT DisplayName,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
,我喜欢union选项是最好和最简单的方法。
选择TOP 901 *
来自openquery(adsisca,\'
选择givenName,
锡
sAMAccountName
来自\'\'LDAP://10.1.2.3:389 \'\'
其中objectCategory = \'\'Person \'\'
和
objectClass = \'\'InetOrgPerson \'\'
和
sAMAccountName <\'\'m \'\'
\')
联盟
选择TOP 901 *
来自openquery(adsisca,\'
选择givenName,
锡
sAMAccountName
来自\'\'LDAP://10.1.2.3:389 \'\'
其中objectCategory = \'\'Person \'\'
和
objectClass = \'\'InetOrgPerson \'\'
和
sAMAccountName> = \'\'m \'\'
\')
,我非常感谢John Sinclair的回答,我决定奉承最高的奉承形式-模仿。这是我对他的解决方案的解释。我没有选择OpenRowSet中的每个查询声明ADSI LDAP连接,而是选择了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,country = c,usnCreated
FROM OpenQuery
(
ADSI,\'\'
SELECT SamAccountName,extensionAttribute1,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,country,usnCreated FROM #ADData order by lanId;
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。