Compatibility mode allows new command? - sql-server

I have a SQL Server 2017 server running a database in 2012 compatibility mode. However when I try using the new to 2017 T-SQL command string_agg(), it works. I would expect a syntax error because string_agg() isn't valid for 2012 mode.
Here is the SQL I'm using:
SELECT
Compatibility_Level,
CASE Compatibility_Level
WHEN 65 THEN 'SQL Server 6.5'
WHEN 70 THEN 'SQL Server 7.0'
WHEN 80 THEN 'SQL Server 2000'
WHEN 90 THEN 'SQL Server 2005'
WHEN 100 THEN 'SQL Server 2008/R2'
WHEN 110 THEN 'SQL Server 2012'
WHEN 120 THEN 'SQL Server 2014'
WHEN 130 THEN 'SQL Server 2016'
WHEN 140 THEN 'SQL Server 2017 <<<'
ELSE 'new unknown - ' + CONVERT(VARCHAR(10), Compatibility_Level)
END AS VersionName
FROM
sys.databases
WHERE
Name = DB_NAME()
DECLARE #x TABLE (col1 INT, col2 VARCHAR(5))
INSERT INTO #x
VALUES (1, 1), (1, 2), (1, 3), (2, 1), (2, 2)
SELECT * FROM #x
SELECT col1, string_agg(col2,', ')
FROM #x
GROUP BY col1
Here is the output:
Compatibility_Level VersionName
------------------- ------------------------
110 SQL Server 2012
(1 row affected)
(5 rows affected)
col1 col2
----------- -----
1 1
1 2
1 3
2 1
2 2
(5 rows affected)
col1
----------- ------------------------------------
1 1, 2, 3
2 1, 2
(2 rows affected)

The purpose of Compatibility Mode is to ensure that statements which were valid in previous versions of SQL Server behave in the same way in newer versions of SQL server.
This includes statements which were previously valid but have become invalid in the new version, and statements which have a different meaning or behave differently between versions.
Statements which were invalid in previous versions are not included in this goal.
Why? Consider upgrading. You first want to convert everything to the new syntax and functions, then when you are satisfied everything is ready, you can raise the compatibility level. If you can't allow things which are valid in the new compatibility level (but invalid or meaningless before) then it becomes difficult to migrate to the higher level.

Related

How to UPSERT a record in SAP ASE Sybase 16?

I am literaly following the SAP documentation 1st example on UPSERT a record in ASE:
https://help.sap.com/viewer/cbed2190ee2d4486b0bbe0e75bf4b636/16.0.3.2/en-US/faf583d9adc547ad8a164bb3f41ea6cd.html
1> select ##version
2> go
Adaptive Server Enterprise/16.0 SP03 PL06/EBF 28334 SMP/P/x86_64/SLES 11.1/ase1
60sp03pl06x/3457/64-bit/FBO/Mon Nov 26 04:33:30 2018
(1 row affected)
1> select * from t1
2> go
a b c
----------- ----------- -----------
1 2 3
(1 row affected)
1> upsert t1(a,b,c) values(1,2,3)
2> go
Msg 102, Level 15, State 181:
Server 'NPL', Line 1:
Incorrect syntax near 'a'.
Does anyone know why am I getting this "Incorrect syntax" error in the UPSERT statment?
Thanks
If the sole intent is to implement upsert capability in ASE then what you want to look at is the merge command.
If the intent is to utilize (a subset of) HANA's SQLScript (in this case the upsert command) for some sort of interoperability requirement, and keeping in mind you may need to modify existing code to work with dual (and incompatible) parsers, then ...
To use (a limited version of) HANA's SQLScript in ASE you first need to create a database that supports the SQLScript parser (see Creating a SQLScript database), eg:
use master
go
create database sqlscript_db
on data_01=10
log on log_01=5
for sqlscript -- enable use of SQLScript parser
go
Running sp_helpdb (from a non-SQLScript db) to verify db status:
use master
go
sp_helpdb sqlscript_db
go
name db_size owner dbid created durability lobcomplvl inrowlen status
------------ ------------- ----- ---- ------------ ---------- ---------- -------- ---------
sqlscript_db 15.0 MB sa 7 Mar 25, 2022 full 0 NULL sqlscript
... snip ... ^^^^^^^^^
You should now be able to use the upsert statement in this new database:
use sqlscript_db
go
create table t1 (a int, b int, c int)
go
upsert t1(a,b,c) values(1,2,3)
go
(1 row affected)
select * from t1
go
a b c
----------- ----------- -----------
1 2 3
NOTE: verified on ASE 16.0 SP04 GA
Verifying SQLScript/upsert does not work in a non-SQLScript database:
use tempdb
go
create table t1 (a int, b int, c int)
go
upsert t1(a,b,c) values(1,1,1)
go
Msg 102, Level 15, State 181:
Server 'ASE400', Line 1:
Incorrect syntax near 'a'.
if your unique key, let's say, is t1.a, then you can use the logic below:
merge into t1 as dest
using (select 1 a, 2 b, 3 c) as src
on dest.a = src.a
when not matched then
insert (a,b,c) values(src.a,src.b,src.c)
when matched then
update set b=src.b, c=src.c

Msg 601... "Could not continue scan with NOLOCK due to data movement".BUT NOLOCK ! - BUG

Strange situation... New physical severs, new install of SQL Server 2019 Enterprise version :
Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64) Sep 24 2019 13:48:23 Copyright (C) 2019 Microsoft Corporation Enterprise Edition: Core-based Licensing (64-bit) on Windows Server 2019 Standard 10.0 (Build 17763: ).
Testing the performance by creating the first database like this :
CREATE DATABASE DB_BENCH
GO
DECLARE #SQL NVARCHAR(max) = N'';
SELECT #SQL = #SQL + N'ALTER DATABASE DB_BENCH MODIFY FILE (NAME = ''' + name + N''', SIZE = 10 GB, FILEGROWTH = 64 MB);'
FROM DB_BENCH.sys.database_files;
SET #SQL = #SQL + N'ALTER DATABASE DB_BENCH SET RECOVERY SIMPLE;'
EXEC (#SQL);
GO
And the objects in the database like this :
USE DB_BENCH
GO
SET NOCOUNT ON;
GO
CREATE TABLE T_TIME_INTERVAL_TIV
(TIV_ID INT NOT NULL IDENTITY PRIMARY KEY,
TIV_GROUP INT,
TIV_DEBUT DATETIME2(0),
TIV_FIN DATETIME2(0))
GO
TRUNCATE TABLE T_TIME_INTERVAL_TIV;
GO
BULK INSERT T_TIME_INTERVAL_TIV
FROM "C:\DATA_SQL\intervals.txt"
WITH (KEEPIDENTITY ,
FIELDTERMINATOR = '\t',
ROWTERMINATOR = '\n');
GO
CREATE VIEW V
AS
SELECT TIV_GROUP AS id, TIV_DEBUT AS intime, TIV_FIN AS outtime
FROM T_TIME_INTERVAL_TIV
GO
The intervals.txt datafile contains 1 million lines.
You can have it at :
https://1drv.ms/t/s!AqvZfiQYoNpBiCD65D4zaRbch5s-?e=UicEYu
The query that produce the bug :
WITH T1 As
(SELECT id, intime
FROM #T
UNION ALL
SELECT id, outtime FROM #T),
T2 As
(SELECT ROW_NUMBER() OVER(PARTITION BY id ORDER BY intime) NN, id, intime
FROM T1 T1_1),
T3 As
(SELECT T2_1.NN - ROW_NUMBER() OVER(PARTITION BY T2_1.id ORDER BY T2_1.intime,T2_2.intime) NN1,
T2_1.id, T2_1.intime intime, T2_2.intime outtime
FROM T2 T2_1
INNER JOIN T2 T2_2
ON T2_1.id=T2_2.id
And T2_1.NN=T2_2.NN-1
WHERE EXISTS (SELECT *
FROM V S
WHERE S.id=T2_1.id
AND (S.intime < T2_2.intime AND S.outtime>T2_1.intime))
OR T2_1.intime = T2_2.intime)
SELECT id, MIN(intime) intime, MAX(outtime) outtime
FROM T3
GROUP BY id, NN1
ORDER BY id, intime, outtime;
We tested this query on 2 different servers... with the same SQL Server installation.
The result is always :
Msg 601, Level 12, State 1, Line ...
Could not continue scan with NOLOCK due to data movement.
With an installation of :
SQL Server 2019 (RTM) - 15.0.2000.5 (X64) Sep 24 2019 13:48:23 Developer Edition (64-bit) on Windows Server 2019 Standard 10.0 (Build 17763: ) (Hypervisor)
There is no problem...
We tested the databases with DBCC CHECKDB () WITH DATA_PURITY. No errors.
Can you reproduce with your different editions/patches (CU) and give me your results for which are alright or not ?
If some of you have already the bug I will add an entry in SQL Azure feedback...
Thanks
After many investigation, we found that it is really a SQL Server bug.
The bug disappear when we execute a :
UPDATE STATISTICS T_TIME_INTERVAL_TIV WITH FULLSCAN;
Or when whe "hint" the query with OPTION (MAXDOP 1)
Sometime a stack dump appear (not Always) showing this type of messages :
A time-out occurred while waiting for buffer latch -- type 4, bp 0000029BA883BDC0, page 9:407, stat 0x10b, database id: 2, allocation unit Id: 422212465393664/140737488683008, task 0x0000029B86723848 : 14, waittime 300 seconds, flags 0x1a, owning task 0x0000029B86713848. Not continuing to wait.
Which is the tempdb. A Stack Dump is systematically recorded on file.
We will call the MS hotline as soon as possible.
Thanks to all of you.

Bug in Ms SQL 2012? TVF giving unexpected result in a outer apply

I'm no expert in Ms SQL, but I came across some really strange behavior in Microsoft SQL Server. I am quite sure it's a bug - but wanted to bring it to more experienced eyes before I conclude that it is. (And I'm not sure how I would go about reporting it to Microsoft if it is).
Environment
##Version =>
Microsoft SQL Server 2012 - 11.0.5343.0 (X64)
May 4 2015 19:11:32
Copyright (c) Microsoft Corporation
Express Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)
Step 1: Create the offending function
I'm going to ask you to create two functions - which should both work the same IMHO, but it seems one of them is acting a little funny.
First, the offending function:
if OBJECT_ID('test_function_bad') is not null
drop function test_function_bad;
go
create function test_function_bad (#val int)
returns table
as return
(select #val as MyBadValue
where #val < 3
);
go
Next, the almost-identical function which works as expected:
if OBJECT_ID('test_function_good') is not null
drop function test_function_good;
go
create function test_function_good (#val int)
returns table
as return
(select #val * 1 as MyGoodValue
where #val < 3
);
Step 2: Create the test table
if OBJECT_ID('tempdb..#test') is not null
drop table #test;
create table #test (id int, val char);
insert into #test
(id, val)
values (1, 'A'),
(2, 'B'),
(3, 'C'),
(4, 'D');
The Bug (maybe)
Run the following code:
select *
from #test a
outer apply dbo.test_function_bad(a.id);
And it gives the result:
id val MyValue
----------- ---- -----------
1 A 1
2 B 2
3 C 3
4 D 4
That's strange... I expected NULLS instead of the "3" and "4" under MyValue.
Why is this function returning values >= 3? It should just return 1 and 2, and nothing else. Right? To confirm this, let's run the following:
select *
from #test a
outer apply dbo.test_function_good(a.id);
This works... It gives the following:
id val MyValue
----------- ---- -----------
1 A 1
2 B 2
3 C NULL
4 D NULL
The Question
Here's the question: Is this really a bug? (I'm guessing some of you experts might be familiar with all sorts of bugs in Ms SQL - but I'm not, this is the first bug I'm seeing. I just want to make sure there's no explanation for this behavior).
Follow up question: If this is a bug, then do I report it to Microsoft? Is there any point in reporting it? Do they care?
Disclaimer: I did try searching for this but didn't find anything.

Compatibility mode in SQL Server 2014?

The application I am using is written by dinosaurs, using *= and =* operators in sql queries. These queries do joins on 10 or so tables, and I have about 500 such queries. And all I have time for is to upgrade the existing software as-is instead of writing any code. So, updating the query builder functions in all of them is not feasible.
Sadly, I am supposed to upgrade the application to use SQL server 2014, instead of 2005. And in 2014, the backward compatibility for a lot of operators is removed. So, I need to enable some kind of compatibility option in SQL server 2014, if it is available. But, I don't know if there is such a thing, and if it is, how to enable it.
Found a query to find the current compatibility setting. Posting it here, in case someone else needs it.
WITH compatversions AS (
SELECT 65 AS MajorVersion ,'SQL Server 6.5' AS ServerVersion
UNION
SELECT 70,'SQL Server 7.0'
UNION
SELECT 80 , 'SQL Server 2000'
UNION
SELECT 90 , 'SQL Server 2005'
UNION
SELECT 100 , 'SQL Server 2008/R2'
UNION
SELECT 110 , 'SQL Server 2012'
UNION
SELECT 120 , 'SQL Server 2014'
)
SELECT TOP 3 ServerVersion,MajorVersion
,ServerVersion + ' ('+ CONVERT(VARCHAR(3),MajorVersion) +')' AS DropDownFormat
FROM compatversions
WHERE MajorVersion IN (
SELECT TOP 3 MajorVersion
FROM compatversions
WHERE MajorVersion <= CONVERT(INT,CAST(##microsoftversion/ 0x1000000 AS VARCHAR(3)) + '0')
ORDER BY MajorVersion DESC)
ORDER BY MajorVersion ASC;
Apparently, SQL server 2014 supports up to 2008 compatibility.

SQL Server 2000 distinguishes between decimal zero 0.00 and -.00 while ADO.NET does not

We're using SQL Server Standard Edition 8.00.760 (SP3) on a Small Business Server 2003 platform.
While tracking down an inexplainable System.Data.DBConcurrencyException for a Strongly Typed DataSet, I discovered the following problem:
Given is this table:
CREATE TABLE [dbo].[Auszahlung](
[auszahlungid] [int] IDENTITY(1,1) NOT NULL,
[spesenkonto] [decimal](10, 2) NOT NULL,
And this query for a row originally inserted with decimals calculated in .NET 2.0 using a Strongly Typed DataSet:
SELECT [auszahlungid], [spesenkonto]
FROM [Auszahlung]
WHERE [auszahlungid] = 35
When run on a Sql Server Management Studio 2005 client, I get this result:
auszahlungid spesenkonto
------------ ---------------------------------------
35 0.00
(1 Zeile(n) betroffen)
But when run on the Query Analyzer on the Sql Server 2000, I get this negative zero:
auszahlungid spesenkonto
------------ ------------
35 -.00
(1 row(s) affected)
Consequently, the queries
SELECT [auszahlungid], [spesenkonto]
FROM [Auszahlung]
WHERE [auszahlungid] = 35
AND [spesenkonto] = 0.00
and (inconsequently on the SQL 2000 Query Analyzer)
SELECT [auszahlungid], [spesenkonto]
FROM [Auszahlung]
WHERE [auszahlungid] = 35
and spesenkonto = -.00
both yield 0 rows, and any row update using a .NET Strongly Typed DataSet will raise a System.Data.DBConcurrencyException because of the the optimistic concurrency restriction.
Questions:
Is this a known bug in MSSQL?
How can I make our system reliable again without sacrificing optimistic concurrency?
Perhaps, when working with SQL2000 driver interprets numeric as float...
Can you try the following workaround
SELECT [auszahlungid], [spesenkonto]
FROM [Auszahlung]
WHERE [auszahlungid] = 35
AND ABS([spesenkonto]) < 0.01

Resources