I need to be able to query Active Directory from SQL Server - see
https://www.mssqltips.com/sqlservertip/2580/querying-active-directory-data-from-sql-server/
The following runs fine:
DECLARE #eid nvarchar(5)
DECLARE #username nvarchar(5)
SET #eid='123'
SELECT #username=sAMAccountName FROM OpenQuery(ADSI,'SELECT sAMAccountName, employeeID FROM ''LDAP://mydomain.com/DC=mydomain,DC=com'' WHERE objectClass = ''User'' AND employeeID=123')
PRINT #username
How to replace the hardcoded 123 value with the actual value of the #eid, so that the modified code will run fine as well?
Thanks!
Annoyingly you have to build the SQL string ahead of time to add a parameter value into it and then execute the OpenQuery using that string. You must execute all of it as you would a dynamic query EXEC sp_executeSQL ...
Here's what I came up with:
DECLARE #eid nvarchar(5), #username nvarchar(5), #Query nvarchar(MAX)
SELECT #eid='123'
SELECT #Query = N'SELECT sAMAccountName FROM OpenQuery(ADSI, ''SELECT sAMAccountName, employeeID FROM ''''LDAP://mydomain.com/DC=mydomain,DC=com'''' WHERE objectClass = ''''User'''' AND employeeID=' + #eid + ''')'
SELECT #Query
EXEC sp_executeSQL #Query, #username OUTPUT
PRINT #username
I may not have the output quite right. Another option you have is to insert the output of the EXEC sp_executeSQL into a temptable and select the username from that value. For more info you can see this question.
Another option (and probably the easiest of all) is to move the WHERE outside of the open query and filter after you get the results back like this:
DECLARE #eid nvarchar(5), #username nvarchar(5), #Query nvarchar(MAX)
SELECT #eid='123'
SELECT #username = sAMAccountName--, employeeID
FROM OpenQuery(AD, 'SELECT sAMAccountName, employeeID FROM ''LDAP://mydomain.com/DC=mydomain,DC=com'' WHERE objectClass = ''User''')
WHERE employeeID = #eid
PRINT #username
I know this is an old question, but here is a way to work with output values (since you'll return only 1 value):
DECLARE #eid nvarchar(5), #username nvarchar(50), #Query nvarchar(MAX)
SET #Query = '(SELECT #username = sAMAccountName FROM OpenQuery(ADSI,''SELECT sAMAccountName, employeeID FROM ''LDAP://mydomain.com/DC=mydomain,DC=com'' WHERE objectClass = ''User'' AND employeeID=' + #eid +') AS tblADSI)'
EXEC sp_executesql #Query , N'#username nvarchar(50) out', #username out
SELECT #username As Outputs
This will assign the result of the OpenQuery execution, in the variable #username.
We tested for Store procedure in MSSQL 2012, but should work with MSSQL 2008+.
Microsoft Says that sp_executesql(Transact-SQL): Applies to: SQL Server (SQL Server 2008 through current version), Windows Azure SQL Database (Initial release through current release). (http://msdn.microsoft.com/en-us/library/ms188001.aspx)
Related
We are using SQL Server 2014 Enterprise with many databases. I have to execute query and get reports / data from every database with EXACT SAME Schema and database starts with Cab
When a new company is added in our ERP project a new database is created with exact schema starting with Cab and incremented number is assigned to it like:
Cab1
Cab2
Cab3
Cab5
Cab10
I can get the database names as:
SELECT name
FROM master.sys.databases
where [name] like 'Cab%' order by [name]
I have to create a Stored Procedure to get data from tables of every database.
How to do that using a Stored Procedure as the databases are created dynamically starting with Cab?
You can use EXEC(#Statement) or EXEC SP_EXECUTESQL if you have to pass parameters.
CREATE OR ALTER PROCEDURE dbo.GetDataFromAllDatabases
AS
BEGIN
DECLARE #T TABLE (id INT NOT NULL IDENTITY(1, 1), dbName VARCHAR(256) NOT NULL)
INSERT INTO #T
SELECT NAME FROM MASTER.SYS.DATABASES WHERE [NAME] LIKE 'Cab%' ORDER BY [NAME]
CREATE TABLE #AllData (......)
DECLARE #Id INT, #DbName VARCHAR(128)
SELECT #Id = MIN(Id) FROM #T
WHILE #Id IS NOT NULL
BEGIN
SELECT #DbName = dbName FROM #T WHERE Id = #Id
DECLARE #Statement NVARCHAR(MAX)
SET #Statement = CONCAT(N'INSERT INTO #AllData (...) SELECT .... FROM ', #DbName, '.dbo.[TableName]')
EXEC(#Statement);
--YOU CAN USE BELOW LINE TOO IF YOU NEED TO PASS VARIABLE
--EXEC SP_EXECUTESQL #Statement, '#Value INT', #Value = 128
SET #Id = (SELECT MIN(Id) FROM #T WHERE Id > #Id)
END
END
A quick and easy dynamic SQL solution would be something like this:
DECLARE #Sql nvarchar(max);
SET #Sql = STUFF((
SELECT ' UNION ALL SELECT [ColumnsList], '''+ [name] + ''' As SourceDb FROM '+ QUOTENAME([name]) + '.[SchemaName].[TableName]' + char(10)
FROM master.sys.databases
WHERE [name] LIKE 'Cab%'
FOR XML PATH('')
), 1, 10, '');
--When dealing with dynamic SQL, print is your best friend...
PRINT #Sql
-- Once the #Sql is printed and you can see it looks OK, you can run it.
--EXEC(#Sql)
Notes:
Use quotename to protect against "funny" chars in identifiers names.
Replace [ColumnsList] with the actual list of columns you need.
There's no need for loops of any kind, just a simple stuff + for xml to mimic string_agg (which was only introduced in 2017).
I've thrown in the source database name as a "bonus", if you don't want it that's fine.
The Order by clause in the query that generates the dynamic SQL is meaningless for the final query, so I've removed it.
I hope that you are all doing well.
I've been working on a project where I need to store data about my college that includes ID numbers, names, contact details etc.
I'm having a bit of difficulty in creating a stored procedure that will be able to insert data into a specified schema.table_name. The procedure must be able to allow the EXEC command to specify which schema you would like the insert data into. The table_name will stay the same for all the 14 schemas. The following code sample is what I have come up with but it doesn't seem to work:
CREATE PROCEDURE AddStudent_proc(#campus varchar(50), #StudentID numeric(4,0), #Name varchar(50), #Surname varchar(50), #ID_numeric numeric(13,0), #Address varchar(100))
AS
BEGIN
DECLARE #dynamic varchar(MAX)
SET #dynamic = 'INSERT INTO ['+quotename(#campus)+'].Student_tbl(
StudentID,
Name,
Surname,
ID_numeric,
Address
)
VALUES('+quotename(#StudentID)+','+quotename(#Name)+','+quotename(#Surname)+','+quotename(#ID_numeric)+','+quotename(#Address)+');'
EXEC (#dynamic);
END
GO
My entire structure can be found
here
I'd appreciate any help on this topic as I am still quite new to SQL as a whole.
Thanks in advance.
You don't need to use quotename for data - as the name of the function implies, it should be used with names (A.K.A identifiers).
Also, when you are using quotename it addeds [ and ] around the value it receives, so no point of adding them again (['+quotename(#campus)+'] in your code).
I would recommend three improvements to the procedure you have now:
Change the data type of #campus to sysname - this is a special data type synonym to nvarchar(128) not null used by SQL Server for all identifiers.
white-list the schema name.
This is a critical change to protect against SQL Injection attacks.
Anything that can't be parameterized needs to be white-listed.
use sp_ExecuteSql instead of EXEC
This will result in a better stored procedure because it eliminates the threat of SQL Injection.
I've written a couple of blog posts that adds some more information and background on this subject: The do’s and don’ts of dynamic SQL for SQL Server and Back to basics: SQL Injection.
Anyway, here's how I would write this procedure:
CREATE PROCEDURE AddStudent_proc(
#campus sysname,
#StudentID numeric(4,0),
#Name varchar(50),
#Surname varchar(50),
#ID_numeric numeric(13,0),
#Address varchar(100)
)
AS
BEGIN
IF EXISTS(
SELECT 1
FROM Sys.Schemas
WHERE name = #campus
)
BEGIN
DECLARE #dynamic nvarchar(4000),
#paramDefinition nvarchar(4000)
SELECT #dynamic = N'INSERT INTO '+ quotename(#campus) + N'.Student_tbl (
StudentID,
Name,
Surname,
ID_numeric,
Address
)
VALUES(#StudentID, #Name, #Surname, #ID_numeric, #Address)',
#paramDefinition =
N'#StudentID numeric(4,0),
#Name varchar(50),
#Surname varchar(50),
#ID_numeric numeric(13,0),
#Address varchar(100)'
EXEC sp_executeSql #dynamic, #paramDefinition, #StudentID, #Name, #Surname, #ID_numeric, #Address;
END
END
GO
I want to create a dynamic query in SQL Server which will run on linked server. I am trying to do it as follows.
USE [MYDB]
GO
DECLARE #company AS nvarchar(50);
DECLARE #id nvarchar(MAX);
DECLARE #query nvarchar(MAX);
SET #company = 'mycompany.com';
SET #query = N'SELECT #csid = id FROM OPENQUERY(LINKSERVER12,
''SELECT id from company where name = #comp'')';
EXECUTE sp_executesql #company_query, N'#comp nvarchar(50), #csid
nvarchar(MAX) OUTPUT', #comp = #company,#csid = #id OUTPUT
In the above script, I want to pass the value for #comp dynamically. For that I tried setting input and output variable while executing SQL with sp_executesql.
I am getting the following error
Syntax error in SQL statement. Syntax error line 1 at or after token .[10179].
Msg 7321, Level 16, State 2, Line 4
An error occurred while preparing the query "SELECT id from company where name = #comp" for execution against OLE DB provider "MSDASQL" for linked server "LINKSERVER12".
The error is happening at the dynamic query
N'SELECT #csid = id FROM OPENQUERY(LINKSERVER12,
''SELECT id from company where name = #comp'')'
I tried replacing #comp in the SQL query with ''#comp'', ''''#comp'''' with no luck. Any help is greatly appreciated.
Just build the string query wihtout parameters.
USE [companyDB]
GO
DECLARE
#companyName AS nvarchar(50)
,#id nvarchar(MAX)
,#query NVARCHAR(MAX)
SET #companyName = 'AMAZON'
DECLARE #idTable TABLE
(
id INT
)
--Repace Server, UID and PWD
SET #query =
N'SELECT
[id]
FROM OPENROWSET
(
N''SQLNCLI''
,N''Server=10.111.1.111;UID=username;PWD=password123;''
,N''SELECT [id]
FROM [companyDB]
WHERE [name] = '''''+#companyName+'''''''
)'
INSERT INTO #idTable
EXECUTE (#query)
SELECT TOP 1
#id = id
FROM #idTable
Currently, sp_helpuser has to be executed for each database of a SQL Server instance separately.
Does anyone have a script that will give sp_helpuser like output for all databases at once?
You can achieve it like below. Not sure about SQL Server 2012 but works in SQL Server 2008 R2. mentioning so cause sp_msforeachdb is undocumented SP and is not guaranteed to work in future release.
sp_msforeachdb 'use [?] print ''?''; exec sp_helpuser;';
EDIT:
See the below post with exact code samples. This is exactly what you are looking for or trying to achieve.
TSQL: Audit user roles for all databases
EDIT1:
Complete code from the post I have mentioned. Have tried myself in SQL2008R2 and warks like charm.
IF OBJECT_ID('tempdb..#user_table') IS NOT NULL
BEGIN
DROP TABLE #user_table;
END;
-- tmp Table to hold the user data
CREATE TABLE #user_table
(
ServerName NVARCHAR(100) NULL,
[Database] NVARCHAR(256) NULL,
UserName NVARCHAR(128) NOT NULL,
GroupName NVARCHAR(128) NULL,
LoginName NVARCHAR(128) NULL,
DefDBName NVARCHAR(256) NULL,
DefSchemaName NVARCHAR(100) NULL,
UserID INTEGER NOT NULL,
[SID] UNIQUEIDENTIFIER NULL
);
DECLARE #sql NVARCHAR(MAX);
SET #sql = '
DECLARE #name SYSNAME,
#sql_string NVARCHAR(MAX);
-- Cursor containing all users for the current database context
DECLARE usr_name CURSOR READ_ONLY FOR SELECT [name]
FROM sysusers
WHERE hasdbaccess = 1
AND [name] NOT LIKE ''#%''
AND [name] NOT IN (''guest'');
OPEN usr_name;
FETCH NEXT FROM usr_name INTO #name;
WHILE (##FETCH_STATUS = 0) -- This loop processes each database
BEGIN
-- if it''s a windows login surround with square brackets
IF (#name LIKE ''%\%'')
BEGIN
SET #name = ''['' + #name + '']'';
END
SET #sql_string = N''EXEC sp_helpuser '' + #name;
INSERT INTO #user_table
(
UserName,
GroupName,
LoginName,
DefDBName,
DefSchemaName,
UserId,
[SID]
)
EXEC(#sql_string);
-- Add Server & database name to dataset
UPDATE #user_table
SET ServerName = ##SERVERNAME,
[Database] = DB_NAME()
WHERE ServerName IS NULL
AND [Database] IS NULL;
-- Get the next database user
FETCH NEXT FROM usr_name INTO #name; -- Get next user
END
-- Clean up
CLOSE usr_name;
DEALLOCATE usr_name;';
-- Add USE database statement to change db context
SET #sql = 'USE ?; ' + #sql;
-- Execute the string for each database
EXEC sp_MSforeachDB #sql;
SELECT *
FROM #user_table
ORDER BY LoginName, [Database];
I am trying to write a custom stored procedure to carry out a select into operation. I want to copy a table (or some columns from a table) from one database to another. I am using SQL Server 2012
CREATE Procedure select_into
AS
Begin
#selection varchar(128),
#newtabname varchar(128)
#fromtabname varchar(128)
Select selection,
INTO table1,
FROM table2,
WHERE selection = #selection AND table1 = #newtabname AND table2 =#fromtabname;
go
EXEC select_into, Ecode, relational_db.dbo.work, dbo.Work_Data;
I get an error message indicating a syntax error near the "." in relational_db.dbo.work.
I would appreciate any help in getting this right
You have a missing comma in parameter list and wrong syntax for procedure declaration. It should be::
CREATE Procedure select_into
(
#selection varchar(128),
#newtabname varchar(128),
#fromtabname varchar(128)
)
AS
Begin
BUT, in addition your syntax for an INSERT INTO contains extra commas and you cannot perform dynamic T-SQL that way.
Can I suggest you first learn TSQL's syntax for SQL Server.
Try something like this ...
CREATE Procedure select_into
#selection NVARCHAR(128),
#newtabname NVARCHAR(128),
#fromtabname NVARCHAR(128)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'Select ' + QUOTENAME(#selection) +
N' INTO ' + QUOTENAME(#newtabname) +
N' FROM ' + QUOTENAME(#fromtabname)
EXECUTE sp_executesql #sql
END