Ignore denied columns in "select * from" - sql

I need to restrict an (support) user from viewing columns in a table (other users should have full access to this table).
So I granted access to only the columns I specified via "GRANT SELECT ON dbo.TestTable (FirstCol, SecondCol, ThirdCol) TO HR_Intern;"
But when I am running a "SELECT * FROM dbo.TestTable;" i got an Access Denied Error for every other column in the table.
The user is doing customer support using the MSSQL Management Studio directly on the database and the errors won't allow the user to edit the data.
Is it possible to just display the columns the user have access to and ignoring every denied column?
Thanks for your help :)

Better to create a VIEW and provide the users access to it. In the VIEW only those columns these users can see should be part of SELECT statement.

As pointed out by others, you need to replace * by an explicit select list.
In case you are worried about having to specify things twice, here is a query to retrieve the list of permitted columns from metadata.
If you like, you can use its result set to generate (part of) the select list for the query on TestTable.
SELECT c.name
FROM sys.columns c
INNER JOIN sys.database_permissions p
ON p.class = 1
AND p.major_id = c.object_id
AND p.minor_id = c.column_id
AND p.state = 'G'
AND p.grantee_principal_id = DATABASE_PRINCIPAL_ID('HR_Intern')
WHERE c.object_id = OBJECT_ID('dbo.TestTable')
Replace DATABASE_PRINCIPAL_ID('HR_Intern') by DATABASE_PRINCIPAL_ID() to get metadata for the currently active user.
The query is still pretty crude; it disregards table-wide grants, and all denies. You may want to experiment with that a bit.

No. That is how security works in SQL. Basically "SELECT *" is not good form, one is supposed to provide a field list.
If the result set would magically change based on the user logged in that would result in a lot of crappy bug reports because applications would suddenly not work. You asked for all fields, that can not be sent, hence an error report.
One workaround is to have a view with a limited number of fields and direct this user to use the views. Obviously that costs time and attention during development.

Related

SSMS - get DDL of all views in a schema

I have a SQL Server database with several schemas, each of them contains several views.
I need to create the same views in other databases so I would like to get the DDL of all the views in a script, generated through SQL.
In Oracle it was quite easy, accessing ALL_VIEWS and referencing the QUERY column.
How can i do the same in SQL Server?
Thanks
EDIT
I know I can right click and get the script of an object in SSMS, I need to do this for 20/30 views, and don't want to do it manually
I'm trying to avoid as much as possible to do manual work. I want to have a query which generates the scripts for all objects in one or more schemas.
This is because the schemas are evolving quickly, with new views being created. I need to reproduce them in several other databases and I'm trying to have a solid procedure for deploying
With the Views node highlighted in Object Explorer, open Object Explorer Details (F8 or Shift+F8 if I recall correctly).
This will open a window with all the views in a list, and you highlight the views you want and right-click > script. Here you can sort by name, filter by schema (probably what you mean by "owner"), etc.
I'm not sure how you can possibly select 20 or 30 views in any scenario without introducing the possibility of human error.
You can write a script that does something similar, with Results to Text, e.g.
SET NOCOUNT ON;
SELECT 'GO' + OBJECT_DEFINITION(object_id)
FROM sys.views
WHERE schema_id = SCHEMA_ID(N'schema_name');
The problem is Management Studio has crippling limits to text output, even after customizing Tools > Options > Query Results > SQL Server > Results to Text and setting that to the max (8,192). So if any of your views are longer than 8,192 characters, you'll need to work around that somehow.
But really, Larnu is right. Your views should be in source control, and that should be your source for deployment, not some manual extraction from the database.
If you want to get the view definitions from a query, you can use sql_modules.
select m.definition
from sys.sql_modules m
join sys.objects o on o.object_id = m.object_id
join sys.schemas s on s.schema_id = o.schema_id
where o.type = 'V'
and s.name in ('your', 'schemas', 'here')
Customize as desired to select the views you want.
You can get views, schemas and definitions by quite standard way:
select * from information_schema.views

How can I get a query of possible login names for SQL job owner?

I'm trying to get the list of all possible login names for a job owner. The following query
SELECT * FROM sys.syslogins
WHERE hasaccess=1
gives me close to what I'm looking for but it returns additional login names that I do not find in the Browse Objects dialog box using SSMS (such as ##MS_AgentSigningCertificate## or BUILTIN\Administrators). I cannot find any logic in sys.syslogins table to discriminate those records. I looked in other logins tables but nothing comes closer than sys.syslogins.
SQL Server is version 10.50 (2008R2) but I'm looking for a query that will give me the results for this version or earlier.
What am I missing?
#Larnu pointed me in the right direction.
Query that solves my question is:
SELECT * FROM sys.server_principals
WHERE [type] IN ('S', 'U')

MS Access SQL update query based on another query

My DB has existing data. I'm trying to implement some sort of security rights system. It doesn't need to be truly secure...just limit what each level can effectively change. Technically...one exists...but it needs to be beefed up.
I need to adjust the existing Rights level for people that are Instructors. I have a query (qInstructors) that lists a DISTINCT query of anyone in the class table listed as an Instructor. There are a total of 38 Instructors.
Now I need to update the User table to adjust the rights of those 38 people...and this is where I'm stuck. A simple update query, no problem. But I must not be searching with the correct term because I can't find anything to help me hammer out the SQL.
UPDATE tblUserList
INNER JOIN tblUserList ON tblUserList.NTID = qInstructors.Instructor
SET tblUserList.Rights = 2
WHERE [NTID]=[Instructor];
When I try to run this, I get a syntax error in the JOIN. This is beyond my SQL knowledge...any leads?
I would suggest doing this using IN:
UPDATE tblUserList
SET tblUserList.Rights = 2
WHERE [NTID] IN (SELECT [Instructor] FROM qInstructors);
The use of JOIN in an UPDATE clause varies by database. The IN version is ANSI standard and should work both in MS Access and in whatever back-end database you might be using.
You were specifying the tblUserlist instead of qinstructors in the join clause.
UPDATE tblUserList
INNER JOIN qInstructors ON tblUserList.NTID = qInstructors.Instructor
SET tblUserList.Rights = 2
Create a query in Design View. Change the type to "Update Query".
Add your target table to the query, and add your existing "Give me instructors" query as well.
Drag a line from the ID in your target table to the corresponding ID returned by your Query.
Drag the field you want to update down to the grid at the bottom. In the "Update To" field, enter "Allowed" or "True" or whatever indicates that something is allowed for instructors.

How to give acces to Reports via SQL

I have a large number of reports where access is controlled on Report level and not folder level.
While one method is to use Server Groups, then this is not the way the setup currently is. Although that would be a good way to manage it.
Using
select C.UserName, D.RoleName, D.Description, E.Path, E.Name
from dbo.PolicyUserRole A
inner join dbo.Policies B on A.PolicyID = B.PolicyID
inner join dbo.Users C on A.UserID = C.UserID
inner join dbo.Roles D on A.RoleID = D.RoleID
inner join dbo.Catalog E on A.PolicyID = E.PolicyID
Where C.UserName = 'XXX'
order by C.UserName
I can get all the reports a user has access to.
So I thought I could generate an SQL statement that can grant access to a user to the same reports as another user has access too, or just a given report.
But I can't seem to wrap my head around how many Places I have to insert data to make this happen.
Does anyone have a solution to this, or a starting point.
Without wanting to destroy something, I thought I could use SQL to grant access to specific reports.
Edit:
It seems I am not the only one wanting to do this:
http://social.msdn.microsoft.com/Forums/en-US/273420db-a506-47bb-9c13-f360e44996bd/bulk-add-users
However it seams the tables are not officially documented, further there are problems concerning the structure and inhertitence of rights, which leaves the RS.exe the only method short of using the webinterface to give users or add user rights to a specific report or folder.

Stored procedure dependencies in SQL Server Management Studio

I don't know much about the MS world, but now it happens to be that I have to use SQL Server Management Studio 2008.
My problem: I have a column in a table, and I need to see all the stored procedures that may be acting on it.
I tried right-clicking and going 'View Dependencies' but that doesn't seem to be returning everything that it should be.
Questions like this one: SQL Server Dependencies have answers that offer 3 types of solutions
Paid third party tools.
Writing your own scripts.
Exporting everything into text files and grepping them.
WTF? Am I missing something obvious? Is that actually how things work? I would imagine that this is a very common use case: you want to alter table and you want to make sure you won't break anything. Or if say you're looking at a new project with a DB for the first time and you want to see how certain columns get populated with stored procedures. Is there actually no quick and easy built-in workflow to do this?
If you need to find database objects (e.g. tables, columns, triggers) by name - have a look at the FREE Red-Gate tool called SQL Search which does this - it searches your entire database for any kind of string(s).
It's a great must-have tool for any DBA or database developer - did I already mention it's absolutely FREE to use for any kind of use??
Use this query:
SELECT ROUTINE_NAME, ROUTINE_DEFINITION
FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_DEFINITION LIKE '%YOUR COLUMN %'
AND ROUTINE_TYPE='PROCEDURE'
I have spent a good amount of time trying to find a way to identify column level dependencies in a quick way without having to search text or use third party applications. The other challenge is finding dependencies across multiple databases where table names may repeat, which will cause false positives when searching SP text.
As of SQL 2008, there is a function that returns dependencies across databases on a field level.
The code below works with a few exceptions:
It will fail if there are stored procedures with invalid references on tables/fields that have been deleted (Incidently I found this to be useful to find SPs that had been accidentally broken by table modifications).
It doesn't find all dependencies in cases where the SP is using temp tables in unusual ways.
In some cases I found that it was returning false positives for complex stored procedures.
MSDN Documentation
This code should be run from within the database where the SP is in order to be able to cross to other database dependencies.
SELECT
--SP, View, or Function
ReferencingName = o.name,
ReferencingType = o.type_desc,
--Referenced Field
ref.referenced_database_name, --will be null if the DB is not explicitly called out
ref.referenced_schema_name, --will be null or blank if the DB is not explicitly called out
ref.referenced_entity_name,
ref.referenced_minor_name
FROM sys.objects AS o
cross apply sys.dm_sql_referenced_entities('dbo.' + o.name, 'Object') ref
where o.type in ('FN','IF','V','P','TF')
I wonder why you cannot see the dependencies via the 'View Dependencies' dialog because it works perfectly fine for me. Nevertheless you can query the 'sys.sql_expression_dependencies' system view and obtain the dependency information that you want.
Example
SELECT OBJECT_NAME(referencing_id),OBJECT_NAME(referenced_id)
FROM sys.sql_expression_dependencies
WHERE referenced_id = OBJECT_ID('XXX')
You can of course project other information that you might need.
List of All Dependent Objects in single query.
select distinct A.name from sys.procedures A inner join sys.sql_dependencies B
on A.object_id = B.object_id;
OR
select distinct A.name from sys.objects A inner join sys.sql_dependencies B
on A.object_id = B.object_id where A.type_desc = 'mentioned your Object Type';