We're working on a product that may or may not have differing license schema for different databases. In particular, a lower-tier product would run on SQLExpress, but we don't want the end user to be able to use a "full-fat" SQL install - benefiting from the price cut. Clearly this must also be the case for other DBs, so Oracle may command a higher price than SQL, for instance (hypothetically).
We're using Entity Framework. Obviously this hides all the neatness of accessing the core schema and using sp_version or whatever it is. We'd rather not pre-load the condition by running a series of SQL commands (one for each platform) and see what comes back, as this would limit our DB options. But if necassary, we're prepared to do it.
So, is it possible to get this using EF itself? DBContext.COnnection.ServerVersion only returns something like "9.00.1234" (for SQL Server 2005). I would assume (though haven't yet checked - need to install an instance) SQLExpress would return something similar - "pretending" it is full-fat. Obviously, we have no Oracle/MySQL/etc. instance so can't establish whether that returns text "Oracle" or whatever.
I can't comment on Entity Framework itself, but for MS SQL Server you can use the T-SQL function SERVERPROPERTY to detect extra information that relates to licence/cost
SELECT
SERVERPROPERTY('LicenseType'),
SERVERPROPERTY('NumLicenses'),
SERVERPROPERTY('EngineEdition'),
SERVERPROPERTY('Edition')
Otherwise, it's simply not exposed in the client code
Related
I have a server called ERP-SERVER, and a server called SQLDEV-SERVER.
They both have a blob instance, but we never copy over the complete blob to the SQLDEV-SERVER as that would be too much data.
So when trying to access a file on our test server, it should first check if that file exists on the SQLDEV-SERVER, and if not check if the file exists on the ERP-SERVER. This is where it goes wrong. This piece of code (SQL) used to work but somewhere along the way it broke. I have narrowed it down to the inter database query just returning completely different results.
so for instance i run this query on the ERP-SERVER instance in SQL management studio:
SELECT count(*)
FROM [erp-server].[Extranet_Blob].[dbo].[FileStorBlob]
this returns 223221 results.
When i run the same query on the SQLDEV-SERVER instance in SQL management studio, it returns 313 results.
It points to the same server and same database, yet a completely different count, which is why it is also not returning the files from the live environment when it is not found on the dev environment.
Any pointers as to where this problem could be situated?
Look very carefully at your linked server definition. When you are running the query on SQLDEV-SERVER it is using the linked server definition of that name rather than necessarily the ERP_Server. Is it possible that someone has fiddled with the definition?
Yesterday, in SQL Server Management Studio (SSMS) (v17.6) I could write and execute:
select * from MyTable;
Today, I now must write:
Select * from myDbName.dbo.MyTable;
However, the old syntax will recognize that the table is there and pull back the headers, but no content. Also, the intellisense with the older syntax.
Yet, in my VB code, I can still use the initial statement shown above.
Why? And, how do I change it back?
You are likely connected to another database on the instance. This commonly happens when the default database for the login isn't set to something explicitly. It defaults the the master database. You'll need to change it in the drop down for intellisense to pick up your table names, and for you to not have to fully qualify the server.database.schema.table.
Also, in the bottom right of your query window, make sure the query window which you are executing your query from is actually connected to the correct database. Since you aren't getting results back, I'd bet that you are also not connected to the correct database when you run your query, but an older or developmental database (where the data is different).
I have a MS Access query that is based on a linked ODBC table (Oracle).
I'm troubleshooting the poor performance of the query here: Access not properly translating TOP predicate to ODBC/Oracle SQL.
SELECT ri.*
FROM user1_road_insp AS ri
WHERE ri.insp_id = (
select
top 1 ri2.insp_id
from
user1_road_insp ri2
where
ri2.road_id = ri.road_id
and year(insp_date) between [Enter a START year:] and [Enter a END year:]
order by
ri2.insp_date desc,
ri2.length desc,
ri2.insp_id
);
The documentation says:
When you spot a problem, you can try to resolve it by changing the local query. This is often difficult to do successfully, but you may
be able to add criteria that are sent to the server, reducing the
number of rows retrieved for local processing.
In many cases you will find that, despite your best efforts, Office Access still retrieves some entire tables unnecessarily and
performs final query processing locally.
However, it's occurred to me that I don't really understand what sort of SQL I should be writing to make both Access and ODBC/Oracle happy.
Should I be writing some sort of generic SQL that Access can understand in a local query AND that can be easily translated to ODBC/Oracle SQL? Is generic SQL a real thing?
What kind of SQL does the ODBC driver use? It depends as typically MS Access has three types of external data connections that interfaces with different SQL dialects each with the ODBC API.
Linked tables that acts like local tables but are ODBC connected data sources and not stored locally. Once they are incorporated in an Access app, these tables can only use MS Access' SQL dialect. They can be joined with local or even other backend tables from other sources.
Hence, why TOP is available in MS Access and not Oracle. You are essentially using Access SQL to manipulate Oracle data. ODBC serves as the origin point of data while Access' Jet/ACE SQL engine does the processing and resultset viewing in cached memory.
Pass-through queries that do not see local tables or anything else in local app's environment. Such queries use the SQL dialect of the connected database here being Oracle.
Hence, why TOP is NOT available in Oracle and double quotes are allowed in column identifiers. Such quoting would fail in MS Access. Essentially, you are using Oracle SQL to manipulate Oracle data in an Access app. You can take the output of the sqlout.txt log and run it in a pass-through query ODBC-connected to your Oracle database.
ADO/DAO Recordsets that are run entirely via code such as VBA and are direct connections to data sources and uses the connecting database's dialect.
Here, you using Oracle SQL to manipulate Oracle data in an Access app via the ODBC API.
In each one of these types, you will have to connect to a backend ODBC data source. You do not even need to use the GUI but can use Access' object library to create linked tables (see DoCmd.TransferDatabase) and pass through querydefs (see QueryDef.Connect or .Execute).
I suspect the sqlout.txt log you see are translations of the ODBC calls to its native dialect.
To build on #Parfait's point #1:
From Microsoft Access Developer's Guide to SQL Server by Mary Chipman and Andy Baron:
Optimizing Access Queries:
There's a common misconception that the Jet engine always retrieves all the data in linked SQL Server tables and then processes the data locally. This is not usually true. Jet is perfectly capable of sending efficient queries to SQL Server over ODBC and retrieving only the rows required. However, in some cases, Jet will in fact be forced to fetch all the data in certain tables first and then process it. You should be aware of when you are forcing Jet to do this and be sure that it is justified. The following are some general guidelines to follow when creating your Access queries:
Using expressions that can't be evaluated by the server will cause Jet to retrieve all the data required to evaluate those expressions locally. The impact of using Access-specific expressions, such as domain aggregate functions, Access financial functions, or custom VBA functions will vary depending on where in your query the expressions are used. Using such an expression in the SELECT clause will usually not cause a problem because no extra data will be returned. However, if the expression is in the WHERE clause, that criterion cannot be applied on the server, and all the data evaluated by the expression will have to be returned.
With multiple criteria, as many as possible will be processed on the server. This means that even if you use criteria that you know include functions that will need to be processed by Jet, adding other criteria that can be handled by the server will reduce the number of records that Jet has to process. Adding criteria on indexed columns is especially helpful.
Query syntax that includes an Access-specific extension to SQL, not supported by the ODBC driver, may force processing to be done on the client by Access. For example, even though SELECT TOP 5 PERCENT is now supported by SQL Server, it is not supported by the ODBC driver. If you use that syntax in an Access query, Jet will need to retrieve all the records and calculate which ones are in the top 5 percent. On the other hand, even though crosstab queries are specific to Access, Jet will translate them into simple GROUP BY queries and fetch just the required data in one trip to the server unless problematic criteria is used.
Heterogeneous joins between local and remote tables or between remote tables that are in different data sources will, of course, have to be processed by Jet after the source data is retrieved. However, if the remote join field is indexed and the table is large, Jet will often use the index to retrieve only the required rows by making multiple calls to the remote table, one fore each row required.
Jet allows you to mix data types within [typo - fix later] of UNION queries and within expressions, but SQL server doesn't. Such mixing of data types will force processing to be done locally.
Multiple outer joins in one query will be processed locally.
The most important factor is reducing the total number of records being fetched. Jet will retrieve multiple batches of records in the background until the result set is complete, so even though you may seem to get results back immediately, a continuing load is being placed on the server for large result sets.
Note: this book is quite old (published in 2000) and is in reference to Jet Engine. I imagine things might be slightly different in newer versions of Access which use ACE, although I don't have a source to back this up.
In a SSIS ETL, I have a query that I need to run on a server/db that does not allow us to create stored procedures.
I would normally use the stored procedure in my variable as the source for my OLE DB source:
However, since we can't put the stored procedure on this server, I was going to store the code for the stored procedure into a variable by executing a SQL statement, retrieving the text from our home database, then use the text stored in this variable as the SQL command for the source:
This way, I can still remotely change the SSIS OLE DB Source object WHERE clause (as long as I don't change the SELECT portion).
I can't imagine that this is very common, so I wanted to get some opinions - is there a better way to do this? I don't want to put all of the code for this SP into the OLE DB Source editor directly because we can't afford to redeploy in case of a WHERE clause update.
You've got the part down that many folks don't do and that's using Variables to drive your package execution. You are further correct in that you can't exactly swap out your columns. To be pedantic, which I am, you can completely change out the query as long as the same metadata is presented.
So, then this question becomes how best to accomplish allowing a package to have a query's filter driven by an external force. Factoring in maintainability, ease of debugging, etc.
My gut reaction is 3 Variables
QueryBase: String. Hardcoded. SELECT * FROM MyTable except of course I'd enumerate my columns
Query: String. EvaluateAsExpression = True Expression: #[User::QueryBase] + #[User::QueryFilter]
QueryFilter: String
So, we use Query in the OLE DB Source much as you have your longer variable name in there. The only downside to this approach, pre SSIS-2012 is the limitation on string length in an expression. It was ... 4k I believe. If you assign a value of 5k characters, it's fine. It's just in the expression language, adding two strings together can't exceed 4k.
I didn't specify what QueryFilter is going to have in it or the magic to get it there. That, I would base on the bigger picture of your environment, usage, etc. but the general concept is that it will eventually turn into WHERE Condition1 IS NOT NULL but maybe in a full reload situation, it becomes an empty string.
So, what are our options for changing the value of QueryFilter
/SET is an optional parameter passed to the invoking process (dtexec.exe) that makes SSIS packages go. If you have a very limited set of choices and aren't interested in building additional infrastructure out to support the parameters, just hard code some examples. Approximately dtexec /file p1.dtsx /set \Package.Variables[User::QueryFilter].Properties[Value];" WHERE Condition1 IS NOT NULL" Save it into .bat files, different sql agent jobs, whatever. Click and run and you're done.
Configuration approach. SSIS offers native ability to use configurations from a SQL Server table, XML, Registry, Parent Package and Environment Variable for 2005 to current edition. The only downside to this approach is that it would not support concurrent execution with different parameters like the first would.
Environment approach. 2012 and 2014, with their new Project Deployment Model, give us the concept of Environments within the SSISDB catalog which is similar to configuration with a SQL Server table but it is done after development is complete and the packages are deployed. It's rather nice as it builds out a history of values used so if someone asks why is the data all wrong, you can write a query to pull back the parameters used and Oh look someone used the initial load filter instead of the daily. Whoopsidaisy. Same concern over concurrent execution and changing values.
Table driven approach. Instead of using the Configuration with SQL Server table backing, you roll your own table and then add into your package an Execute SQL Task to retrieve the filter, Single Row, into our QueryFilter Variable.
Script Task. Use whatever floats your boat to determine what the filter should be.
Message Queue. They have built in a Message Queue Task and might be of use here if you're already doing it. Otherwise, too much effort to manage
I am a new database intern working with a access front end and SQL server backend database. The database was custom made for the company. One of my assignments is to take scripts and apply them to make four new tables. I am aware that I need to make a new query for each new table but I don't know if I should make the query in SQL server management studio or the frontend access program. I have tried copying and pasting the given scripts into a new query in access but I get an error message "invalid SQL statement expected 'DELETE', 'INSERT'...". I decided to try to break done the program a little bit and tested the first line
IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id =OBJECT_ID(N'[dbo] .[FK_tblInstrumentInterfaceLog_tlkpInstrument]') AND parent_object_id = OBJECT_ID(N'[dbo].[tblInstrumentInterfaceLog]'))
but the same error message keeps popping up. I even tried just SELECT * FROM sys.foreign_keys, and I got the error message "could not find file...". I am very much a beginner and any guidance would be appreciated.Basically am I supposed to be applying these scripts the server SQL database or on the front end access program?
Are you using a pass-through query? i.e. not just a select query. Access needs to know where to send the query and since you are using TSQL not Access SQL this needs to be executed on the server.
Normally when you query a linked table the information of how to get the data (the connection string) is tied to the table. But for this kind of query you'll probably need to tell Access explicitly. Unless you are using an ADP/ADE, then the connection info travels with the program not the table.
As a general rule, you use SQL management studio (SSMS) to create and run those scripts. So the general accepted approach here is such scripts will not be placed in the front end. As noted such scripts if for some reason must be placed in the front end, then you have to create them as pass-though, but EVEN in this case you want to use the SSMS to create such quires.
So the answer here is you create the new scripts and make table queries in the back end, or in this case using the SQL server management studio.
The syntax checking, query editor etc. in recent versions of SSMS now has auto-complete etc. and you can test/write/update those scripts in SQL server. Once you have such a query or even several of them, then the resulting “several” statements can be pasted into a front end query that been created as pass-though. If you do not use a pass-though query, then you are creating and using and assuming client side SQL (JET (now called ACE)).
The client side has it own version of SQL syntax, and it is NOT 100% compatible with the SERVER SIDE. If you writing SQL in the client that is NOT pass though, then you using a linked table to SQL server. These linked tables thus will use local (JET/ACE) based SQL queries. The ODBC driver thus translates this SQL into server side compatible syntax. However the JET/ACE sql syntax is very limited when compared to SQL server and no server side commands exist in this SQL syntax for the client data engine (JET/ACE)
So for many quires, you will and can simply build such queries using the Access query builder.
However for SQL that needs to run 100% server side then such quires has to be setup as pass-though and are in most cased built + tested using SSMS.