How to get table's metadata from linked server (SQL Server) - sql

How to get tables metadata from linked server/another database? The query below works ideally when running on the main server, but returns null if calls remote server or even another database.
select object_name(major_id)
from server.bd1.sys.extended_properties
Probably, it is caused that the specific path for metadata functions (like object_name()) is not defined. Hence, functions take data not from remote server/DB, but server and DB they are launched.
If it is true, would you prompt the specific path (DB, schema) of metadata functions that I could define path explicitly.
Thank you for help.

Solved by using direct query to the tables with metadata except using builtin functions
select
c.name schma
,a.name tble
,b.name desc_categ
,b.value desc_name
from server.db.sys.objects a
join server.db.sys.extended_properties b on a.parent_object_id = b.major_id
join server.db.sys.schemas c on a.schema_id = c.schema_id

Related

MS Access SQL error with Update Query

working on linking data between a SQL Server Database and MS Access. Right now someone is manually calculating Data from a SQL Database report and entering this into Access to run other reports within Access.
I have created a pass through query to pull the relevant information into an Access Table from the SQL Database( all working nicely )
Now I need to update the existing Access Tables with Data retrieved from the SQL pass through. I have tried a number of different queries all fussing at me for various reasons. Here is an example of the latest query that will get me what I need. This works if I setup a Sandbox in SQL Server and run it MSSQL Management Studio, but will not work in access
UPDATE JT
SET JT.ContractAmt = SBD.TotalSum
FROM JobTable_TEST AS JT
INNER JOIN (
SELECT Sum( Main.amt ) as TotalSum, Main.job
FROM Main
GROUP BY Main.job
) AS SBD
ON SBD.job = JT.JobNumber
In Access the Above Generates the following error "Syntax error( missing operator) in query expression.
Updating following attempt at using SQL Passthrough to run the update Query.
I updated my Query to do this directly from a Passthrough SQL Statement as suggested and get the following error.
ODBC--call failed.
[Microsoft][SQL Server Native Client 11.0][SQL Server]Invalid object name 'TableName'.(#208)
Here is what the pass through query i used looked like.
UPDATE AccessTable
SET AccessTable.amt = SQLResult.Total
FROM TableName AS AccessTable
INNER JOIN ( SELECT SUM( SQLTableA.amt) as Total, SQLTableA.job
FROM SQLTableA
LEFT OUTER JOIN SQLTableB ON (SQLTableA.company = SQLTableB.company)
AND (SQLTableA.job = SQLTableB.job)
GROUP BY SQLTableA.job
) AS SQLResult
ON SQLResult.job = AccessTable.JobNum
hopefully that better describes where my tables are located and how my update needs to happen, and maybe someone can point out how this is wrong or if it will even work this way.
Any suggestions would be greatly appreciated
It appears your subquery, aliased as SBD, is missing a job_no column. Therefore you aren't going to be able to join on it.

How to Join two MongoDB Collections with the Unity JDBC driver?

From the Unity JDBC download page:
If the SQL query requires joins or functions not supported by MongoDB, then the query is promoted to UnityJDBC (trial version). The UnityJDBC trial version has no expiration date and is fully functioning except that it is limited to returning up to 100 results.
However, when I try to join two tables using any syntax like
SELECT * from a, b WHERE a.id = b.id
SELECT * from a INNER JOIN b ON a.id = b.id
SELECT * from a INNER JOIN b USING (id)
Results in the following:
Exception: java.sql.SQLException: ERROR: No schema defined. The default schema location is _schema in the current database. You need write permission to create this collection. Otherwise, use the schema parameter to set a file location (e.g. schema=mongo.xml) to store the schema. See connection parameters at http://www.unityjdbc.com/mongojdbc/ for more details.
java.sql.SQLException: ERROR: No schema defined. The default schema location is _schema in the current database. You need write permission to create this collection. Otherwise, use the schema parameter to set a file location (e.g. schema=mongo.xml) to store the schema. See connection parameters at http://www.unityjdbc.com/mongojdbc/ for more details.
at mongodb.conn.ServerConnection.processMongoWithUnity(Unknown Source)
at mongodb.conn.ServerConnection.executeQuery(Unknown Source)
at mongodb.jdbc.MongoStatement.executeQuery(Unknown Source)
at mongodb.ExampleMongoJDBC.doQuery(ExampleMongoJDBC.java:222)
at mongodb.ExampleMongoJDBC.main(ExampleMongoJDBC.java:66)
Ok, so I took a look in the readme and found it mentioning the code/test/dspec/ folder with some files related to schemas. I opened a few up, they are highly detailed xml files of all the collections mapping them to relational data types.
Do I have to write one of these out, or is there a way to auto generate it?
I received a (fast) response from the Unity team.
The MongoDB JDBC driver has two modes. For single collection queries, it does not build a schema. For queries involving joins or expressions it builds a schema and by default stores it in the _schema collection in the current Mongo database. If you do not have permission to write to the database, an error is thrown.
As mentioned in the error, you can set the schema parameter to be a local file name (such as mongo.xml) and it will store it on your computer rather than in the Mongo database. You could also use an account that has write permissions.
To make this work, add schema=mongo.xml to your connection URL like this:
jdbc:mongo://localhost/dbname?schema=mongo.xml?rebuildschema=true
After this is done the first time, you can remove the rebuildschema=true or it will rebuild it every time.
The only thing I'm confused about is that I'm using a database which doesn't require authentication. I even made a user with write permissions, connected to him, and still received the above error.
--EDIT
I realized that you could also just do jdbc:mongo://localhost/dbname?rebuildschema=true. If the schema hasn't been created, then the previous error will be thrown.

Ignore denied columns in "select * from"

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.

Script to get detached databases from folder and subfolders

Is there a way to find out if SQL Server databases are attached from a directory with many subfolders apart from going to properties of each .mdf and checking if it is attached?
Is there a script that can check folders/subfolders an write to file to accomplish this?
THanks all.
This should be fairly easy to do:
firstly i would query the database server sysdatabase table to locate all databases you have attached and there corresponding file names and store in a temporary table.
Using the xp_cmdshell function exec a dos DIR command to list all MDF/LDF files with the right switch to navigate folders and store the results in another temporary table
Compare these tables and you will be able to find what files are not attached.
I have done similar tasks before and used both SSIS and Direct Transact-SQL
T
When you need to read the file system from T-SQL, I find that CLRs have the most flexibility. They give you full access to the system.io namespace as well as support for table valued functions.
Have a look at the SQL Server CLR IO Utility. There is a full solution here which enables filesystem functionality that is not easily available with the frowned upon xp_cmdshell.
The table valued function, SQLIO_fnGetFiles, can be used to join to the sys.master_files table and return files which are no longer attached to a database. In this example, the CLR is deployed to a database named CLRS:
USE master
SELECT fs.PATH FileSystemPath
, FileIsAttached = CASE WHEN d.name IS NULL THEN 'YES' ELSE 'NO' END
, d.name DatabaseName
, mf.name FileLogicalName
, mf.physical_name DatabaseFilePath
, FileType = CASE mf.type_desc WHEN 'ROWS' THEN 'DATA' ELSE mf.type_desc END
FROM CLRS.dbo.SQLIO_fnGetFiles('L:\MSSQL\','*df',1) fs
LEFT OUTER JOIN sys.master_files mf ON fs.PATH = mf.physical_name
LEFT OUTER JOIN sys.databases d ON d.database_id = mf.database_id
There are also other methods (powershell, .net, ssis,...) to accomplish this. My experience is that once you deploy the IO Utility solution, you'll find many other time saving uses for it.

How to create Sql Synonym or "Alias" for Database Name?

I'm using ms sql 2008 and trying to create a database name that references another database. For example 'Dev', 'Test', 'Demo' would be database names that i could reference from my multiple config files, but each name would point to another database such as 'db20080101' or 'db20080114'.
[Edit]Some of the configs are for applications that i control the code and some aren't (ex. MS Reporting service datasource file configs)[/Edit]
It seems that sqlserver only supports synonyms for View,Table,Sproc, or Function. And Alias' are for table and column names.
Is there a way to do this that i missed in the docs?
Any one have any suggestions on a workaround?
use 3 part notation and alias up to the table, example
select * from tempdb.dbo.sysobjects a
join master.dbo.sysobjects b on a.id = b.id
There is a way to simulate this using a linked server. This assumes you have two SQL servers with the same set of databases one for development/test and one live.
Open SQL Server Management Studio on your development/test server
Right click Server Objects > Linked Servers
Select New Linked Server...
Select the General page
Specify alias name in Linked server field - this would normally be the name of your live server
Select SQL Native Client as the provider
Enter sql_server for Product Name
In Data Source specify the name of the development server
Add Security and Server Options to taste
Click OK
The above is for SQL Server 2005 but should be similar for 2008
Once you've done that you can write SQL like this:
SELECT * FROM liveservername.databasename.dbo.tablename
Now when your scripts are run on the development server with the linked server back to itself they will work correctly pulling data from the development server and when the exact same scripts are run on the live server they will work normally.
I've done something similar to this using another config file.
The new config file maps your generic name to all of the information needed to connect to that database (db name, user name, password, etc.) and then your connection function takes your generic name as an argument.
db.config:
DEV_DB_NAME = db20080101
DEV_DB_USER = dev_user
DEV_DB_PASS = dev_pass
TEST_DB_NAME = db20070101
TEST_DB_USER = test_user
TEST_DB_PASS = test_pass
connection code:
db_connection get_connection(string prefix) {
db_connection db_conn = new db_connection;
string db_name = get_config_value(config_path, prefix + "_DB_NAME");
string db_user = get_config_value(config_path, prefix + "_DB_USER");
string db_pass = get_config_value(config_path, prefix + "_DB_PASS");
db_conn.connect(db_name, db_user, db_pass);
return db_conn;
}
Then you just call get_connection() with your db alias as the argument.
I know this probably will not help in all situations, but you still have the option of using views. You can insert, delete, update, select into a view as long as it has a proper identity key (Primary Key). If you point it to another database, you should drop and recreate to get the different schema (in case you're working between production and test while making changes to the schema in test and/or production.
Synonyms are useful for when you're going to another database and have a 3 or 4 part name, but when you want to make it so you can have a set name, a linked server will also work which will let you use a fixed name if the table names are the same in both databases and you're just pointing between prod and test.