Detect Sql Express From TSQL - sql-server

I need a safe (i.e consistent, robust) way of detecting whether or not the sql server I'm accessing is Sql Express. I think I'd prefer to be able to do this from TSQL, since I already have a connection string and all the libraries I need to execute TSQL (this should help avoid issues with whether or not WMI is installed/running, the user has permissions to access the registry etc).
Does anyone know of a way to do this ?
Thanks.
PS: Basically I want to do this so I can monitor my database size against the 4gb limit and take action when I approach it... but if I'm running on a full Sql Server edition then I don't want the code to worry about it since there is no (practical) hard coded limit. I could put in a manual setting in my program, but it would be much nicer if the code just did the right thing automatically, hence the need to know if the server is the 'Express' edition or not.

Use
SELECT SERVERPROPERTY('EditionID')
or
SELECT SERVERPROPERTY('Edition')
to detect which version of SQLServer is running.
http://msdn.microsoft.com/en-us/library/ms174396.aspx

This will return 0 if it's not, and something non-zero (126 here) if it is:
select charindex('Express Edition',##version)
Example in a boolean context:
if (select charindex('Express Edition',##version)) > 0
begin
print 'Express edition!'
end
else
begin
print 'Not Express edition!'
end

The SERVERPROPERTY function was already mentioned in multiple other answers, but there's a better solution than checking if a string contains "Express Edition": the EngineEdition argument, which returns an int value.
Quote from the link:
EngineEdition
Database Engine edition of the instance of SQL Server installed on the
server.
1 = Personal or Desktop Engine (Not available in SQL Server 2005 and
later versions.)
2 = Standard (This is returned for Standard, Web, and Business
Intelligence.)
3 = Enterprise (This is returned for Evaluation, Developer, and both
Enterprise editions.)
4 = Express (This is returned for Express, Express with Tools and
Express with Advanced Services)
5 = SQL Database
6 - SQL Data Warehouse
Base data type: int
So you can check for Express Edition like this:
if SERVERPROPERTY('EngineEdition') = 4
begin
select 'Express'
end
else
begin
select 'not Express'
end

There are a number of ways:
EXEC sp_server_info 2
Or
SELECT ##version
Or
SELECT serverproperty('ProductVersion')
You Can Also do this:
DECLARE #ver nvarchar(128)
SET #ver = CAST(serverproperty('ProductVersion') AS nvarchar)
SET #ver = SUBSTRING(#ver, 1, CHARINDEX('.', #ver) - 1)
IF ( #ver = '8' )
SELECT 'SQL Server 2000'
ELSE IF ( #ver = '9' )
SELECT 'SQL Server 2005'
ELSE
SELECT 'Unsupported SQL Server Version'
More info at: http://blog.devstone.com/aaron/default,date,2006-12-15.aspx

You can use SERVERPROPERTY('Edition') which will return "Express Edition"

What happens in SQL Server Express if you don't monitor the size, but get to the limit? Are there warnings first? Events in the event log?
If so, then you might do better to allow SQL Server to issue the warnings, and then just listen to them. The same might well apply for a SQL Server Enterprise installation if a disk gets full.

Related

Why does SQL Server HASHBYTES work differently from Oracle STANDARD_HASH?

Any idea why the two hashing functions in SQL Server and Oracle yield different results when hashing the non-breaking space character?
Oracle select standard_hash('a ', 'MD5') from dual; results in 25EF28EB5A5BE667C6222418E9E27E8E and doesn't match SQL select HASHBYTES ('MD5','a '); results in CE8F03020C81133B3A082F8051EB9FF6. Note the space after the input 'a' is a non-breaking space character.
Is there any good source that can lay out the differences?
This appears to be a character set or "collation" issue, where Oracle is in UTF-8 and SQL Server is in Latin 1252. My solution was to CONVERT the value to Windows Latin-1252 in Oracle before calculating the hash: select STANDARD_HASH(CONVERT('a ','WE8MSWIN1252'), 'MD5') from dual.
To find my collation/character set I did SELECT collation_name FROM sys.databases WHERE name = 'MY_DB_NAME'; in SQL Server and select * from nls_database_parameters where parameter='NLS_CHARACTERSET'; in Oracle.
First of all you need to establish which one is actually yielding "different" results:
Using your favourite search engine to find online hash generators and testing results.
External Resources
https://passwordsgenerator.net/md5-hash-generator/ - 99020CB24BD13238D907C65CC2B57C03
https://www.md5hashgenerator.com/ - 99020cb24bd13238d907c65cc2b57c03
https://www.miraclesalad.com/webtools/md5.php - 99020cb24bd13238d907c65cc2b57c03
SQL Server
select HASHBYTES ('MD5', 'a ')
SQL Server 2014 SP3 (12.0.6024.0) - 0x99020CB24BD13238D907C65CC2B57C03
SQL Server 2019 (15.0.2080.9) - 0x99020CB24BD13238D907C65CC2B57C03
Oracle (using https://dbfiddle.uk/)
select standard_hash('a ', 'MD5') from dual;
Oracle 21c - 0x99020CB24BD13238D907C65CC2B57C03
Oracle 18c - 0x99020CB24BD13238D907C65CC2B57C03
Oracle 11gR2 - "ORA-00904: "STANDARD_HASH": invalid identifier"
Conclusion
You can see that your Oracle produced answer differs even from other Oracle answers. What version of Oracle are you running? What other options are set, such as collation etc.?

why 12c with extended varchar2 limit still converting sql server varchar(max) to long

Oracle version 12.1.0.2
max_string_size=extended
I am using sql server ODBC to connect to sql server database via Oracle gateway to sql server, the connection is working fine and i am able to access sql server tables.
However, as per Oracle documentation starting 12c and with extended limit on varchar2 data type the conversion of sqlserver varchar(max) to oracle Long will only happen if the length of sql server data is more than 32k.
My sql server table has few columns defined as varchar(max) in and all of those i see getting converted to LONG when i try to describe the table over dblink.
I need to load the data from sql server to oracle and the above problem is making it very difficult as more than one long columns can not be copied over dblink.
Any help will be deeply appreciated.
I created a view on the SQL server side that uses substr(column,1,4000) to fit within the old Oracle max 4000 character length. This worked quite well with Oracle 11.
I am in the process of migrating to a new Oracle 18 instance that uses character set AL32UTF8 instead of WE8MSWIN1252. The exact same SQL is now getting:
ORA-28500: connection from ORACLE to a non-Oracle system returned this message:
[Microsoft][ODBC Driver Manager] Program type out of range {HY003}
ORA-02063: preceding 2 lines from CEAV195
Fortunately I don't have a tight deadline for working this out.
Comment: I am now getting
[Error] Execution (8: 17): ORA-00997: illegal use of LONG datatype
despite using the following in the view on the SQL Server side:
cast(substring(cr.response,1,2000) as varchar(2000)) response
As I said earlier, this worked perfectly fine with Oracle 11 and the WE8MSWIN1252 character set.
I hit the same issue and found this solution elsewhere
set serverout on
DECLARE
l_cursor BINARY_INTEGER;
l_id VARCHAR2(60);
l_temp VARCHAR2(250);
l_notes VARCHAR2(32767);
BEGIN
l_cursor := DBMS_HS_PASSTHROUGH.open_cursor#remotedb;
DBMS_HS_PASSTHROUGH.parse#remotedb(
l_cursor,
'select "RecId","Notes" from "MySqlServerTable"'
);
LOOP
DBMS_HS_PASSTHROUGH.get_value#remotedb(l_cursor, 1, l_id);
DBMS_HS_PASSTHROUGH.get_value#remotedb(l_cursor, 2, l_notes);
DBMS_OUTPUT.put_line(l_id || ' ' || l_notes);
END LOOP;
exception
when others then
DBMS_HS_PASSTHROUGH.close_cursor#remotedb(l_cursor);
raise;
END;
/

Call DB2 stored procedure from SQL Server 2008 linked server

I have a linked server from SQL Server 2008 to DB2. The linked server uses the IBM Drivers and not the Microsoft ones.
So this works from SQL Server:
exec ('call RERTEBT.GET_DEFINITION (69,'''','''')') AT MyLinkedDB2Server
This also works using openQuery... which is returning different data from another table
select
RPMG_ETY_CD,
ROW_CU_DATA_IN,
ROW_EF_DT,
ROW_XPR_DT,
RPMG_ETY_NM
from
OPENQUERY
(MyLinkedDB2Server,
'select
RPMG_ETY_CD,
ROW_CU_DATA_IN,
ROW_EF_DT,
ROW_XPR_DT,
RPMG_ETY_NM
from RERTEBT.V1RERRMM')
However I cannot get a select to return data with the DB2 Sproc
This fails -
SELECT FLT_DFN_ID, FLT_SRC_DFN_NO, FLT_VRSN_NO, FLT_STAT_CD, FLT_TY_CD, FLT_NAME
FROM OPENQUERY (MyLinkedDB2Server,
'call RERTEBT.GET_DEFINITION 69,'''','''')')
Has anyone any idea on how to call a DB2 stored procedure from SQL Server Linked server and return the data or can this be done. I read somewhere the DB2 cant do this but haven't seen any real documentation on it.
Thanks D
More explanation for Josef's answer:
You need to right-click the linked server's "properties"
then -> "Server option"
The "RPC" and "RPC Out" option in the right pane need to be TRUE
-- edited -- I can't comment on the answer yet (don't have 50 rep)
Your should be able to do this:
EXEC ('{CALL RERTEBT.GET_DEFINITION (69,'''','''')}') AT MyLinkedDB2Server;
Or even cleaner with passing variables
EXEC ('{CALL RERTEBT.GET_DEFINITION (?,?,?)}', 69, '', '') AT MyLinkedDB2Server;

Execute query once in SQL Server despite being called mutiple times

I have a situation where a query might be called multiple times from multiple users, but I only want it to run once (per week) against the database. The environment is SQL Server Express so scheduling via SQL Server Agent is not an option. It needs to be 2005 compatible. I'd like to make it as lightweight as possible too, so I'm asking for suggestions. Ideally a database wide declared variable - but I don't think that SQL Server supports such a beast? Thanks
Try something like this:
IF NOT EXISTS ( -- Check if you have the current week content
SELECT *
FROM WeeklyTable
WHERE
DATEPART(YEAR, DateCr) = DATEPART(YEAR, GETDATE())
AND
DATEPART(WEEK, DateCr) = DATEPART(WEEK, GETDATE())
)
BEGIN
-- delete old content
DELETE WeeklyTable
-- insert new content
INSERT INTO WeeklyTable (MyID, MyField1, ... , MyFieldN, DateCr)
SELECT
MyID, MyField1, MyField2, GETDATE()
FROM MainTable
END
You can create indexes you need for the WeeklyTable.
One option would be SQL Scheduler as a add-on to SQL Server Express.
The other option would be to create a small command-line utility that does the querying and schedule that using the Windows Scheduler on the machine where SQL Server Express is installed.
With either of the two setups, you could select the values / numbers you need into a result table once a week, and any requests during the week would be satisfied from that one result table. SQL Server doesn't have "server-wide" variables - but you can always define a table for that purpose...

Version Agnostic SQL Server Script/Statement that detects existence of a specific database

Due to the packaged nature of the release, a SQL Server script (well more of a statement) needs to be created that can execute correctly on SQL Server 7.0 thru 2008 which can essentially achieve this:
if exists(select * from sys.databases where name = 'Blah')
Reasons this is difficult:
SQL 7 'sys.databases' is not valid
SQL 2008 'sysdatabases' is not valid
I stupidly parsed out the version number using serverproperty, to allow an IF depending on the version:
if (select CONVERT(int,replace(CONVERT(char(3),serverproperty ('productversion')),'.',''))) >= 80
Then discovered serverproperty does not exist under SQL 7.
Note that the SQL can be remote from the install, so no futzing around on the local machine - reg entries/file versions etc is of any use.
SQL Server error handling (especially 7.0) is poor, or maybe I don't understand it well enough to make it do a kind of try/catch.
I am now getting problem blindness to this, so any pointers would be appreciated.
Thanks,
Gareth
Try
USE database
and test ##ERROR.
USE database
IF ##ERROR <> 0 GOTO ErrExit
logic ...
RETURN 0
ErrExit:
RETURN 1
(or RAISERROR, or ...)
Thanks G Mastros
This looks like it might yield a 100% solution. It is available under SQL 7.
I need to complete and test, but at first glance I think it will fly.
Here's the draft code FYI.
create table #dwch_temp
(
name sysname
,db_size nvarchar(13)
,owner sysname
,dbid smallint
,created nvarchar(11)
,status nvarchar(600)
,compatibility_level tinyint
)
go
insert into #dwch_temp
exec sp_helpdb
if exists(select name from #dwch_temp where name = 'DWCHServer')
-- run the code
drop table #dwch_temp
You could try a TRY... CATCH around a USE [DatabaseName].
I don't have access to a SQL 7 instance, but I encourage you to try:
sp_helpDB
I know this works on sql 2000 and sql 2005 to get a list of databases. I suspect it works on SQL 7, too.
sysdatabases is a remnant from the Sybase era and is still present in SQL 2008 (although deprecated). You can check for the existence of a database with a query like this:
IF EXISTS (SELECT 1 FROM master..sysdatabases where name = 'Blah')

Resources