We updated our SQL Server database from 2012 to 2016 recently.
Now, our very old C++ programs run into an issue. Very old means, there is no one left who can maintain the code anymore.
The problem is: In the code itself, the Date Fields are initialized as
RFX_Date(pFX, _T("[CREATION_DATE_CENTRAL]"), m_CREATION_DATE_CENTRAL);
The query, which is executed onto the database looks like this:
EXECUTE sp_executesql
N'SELECT * FROM ADDON_Table
WHERE NR = #number
and CREATION_DATE_LOCAL = #date1
and CREATION_DATE_CENTRAL = #date2',
N'#number int, #date1 datetime2, #date2 datetime2',
9817434, '2019-11-19 10:03:22.000', '2019-11-24 19:24:38.5270000';
At least one row should be returned. But the query returns no row.
I figured out, that after changing the datatype of date2 from datetime2 to datetime returns a row.
EXECUTE sp_executesql
N'SELECT * FROM ADDON_Table
WHERE NR = #number
and CREATION_DATE_LOCAL = #date1
and CREATION_DATE_CENTRAL = #date2',
N'#number int, #date1 datetime2, #date2 datetime',
9817434, '2019-11-19 10:03:22.000', '2019-11-24 19:24:38.527';
My conclusion is, that somethings happened after updating the DB to 2016 with the datetime/datetime2 implementation.
Don't know if our Application/ODBC uses from now on datetime2 instead of datetime. Or is there a new behavior of the sp_executesql.
It would be great if someone can help me.
Related
I've run this SQL query on two different servers:
declare #test as datetime='2020-05-06 00:00:00'
select Convert (nvarchar,#test)
The results were different on the two servers:
May 6 2020 12:00AM
Jun 5 2020 12:00AM
I know the reason behind this, when SQL Server is reading the string that I passed 2020-05-06 00:00:00 and converting it to DateTime in the declare statement, it's using the default date style.
Am I able to configure this default style, or in other words, how is default date style chosen in SQL Server when converting the varchar to datetime? Is it from the windows regional settings or some other configurations inside SQL Server?
It uses a style based on the language. Basically, for the date above, if you're American then the date will be read as yyyy-MM-dd hh:mm:ss, however, if use over languages, then it's be (stupidly) read as yyyy-dd-MM hh:mm:ss.
If you are using strings for dates (like your literal here) then aim to use an unambiguous format. In SQL Server, regardless of data type and language, those are yyyy-MM-ddThh:mm:ss.nnnnnnn and yyyyMMdd.
If you're convert to an (n)varchar, always use a style code (and a length for your varchar) for consistent results.
So, for your value, you can run the below to find out what the default conversion value would be for all the languages on your instance:
DECLARE Languages CURSOR FOR
SELECT alias
FROM sys.syslanguages;
DECLARE #Alias sysname,
#SQL nvarchar(MAX);
CREATE TABLE #ConvertedDates (Alias sysname, dt datetime, converted nvarchar(25));
DECLARE #dt datetime = '2020-05-06T00:00:00'
OPEN Languages
FETCH NEXT FROM Languages
INTO #Alias;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQL = N'SET LANGUAGE ' + QUOTENAME(#Alias) + N'; INSERT INTO #ConvertedDates(Alias,dt,converted) VALUES(N' + QUOTENAME(#Alias,'''') + ',#dt,CONVERT(nvarchar(25),#dt));';
EXEC sys.sp_executesql #SQL, N'#dt datetime', #dt;
FETCH NEXT FROM Languages
INTO #Alias;
END;
CLOSE Languages;
DEALLOCATE Languages;
SELECT *
FROM #ConvertedDates;
DROP TABLE #ConvertedDates;
Yes, that is a Cursor. I wanted to ensure that each dynamic statement ran by itself, to ensure language was preserved for each conversion.
I have a simple stored procedure where part of it I want to set 2 variables, 1 for the current time and the other for the current date. I need them in hhmm format for the time and yyyyMMdd format for the date.
Here is the code I have so far:
BEGIN
DECLARE #d AS DATETIME
DECLARE #t as TIME
SET #d = GETDATE()
SET #t = SYSDATETIME()
But everything I've tried to use to change the format of those 2 variables does not help me out. The only examples I've found online is for formatting values in regular queries.
Can anyone point me in the right direction as far as what I should do to get these values? Thanks in advance.
If 2012+ you can use Format()
Example
DECLARE #d as varchar(8) = format(GetDate(),'yyyyMMdd')
DECLARE #t as varchar(4) = format(SYSDATETIME(),'HHmm') -- use hh for 12 hour time
Select #d,#t
Returns
(No column name) (No column name)
20180511 1738
For 2005
DECLARE #d as varchar(8) = convert(varchar(10),GetDate(),112)
DECLARE #t as varchar(8) = replace(left(convert(varchar(25),SYSDATETIME(),108),5),':','')
I am trying to combine a SmallDateTime field and a Time value (result of a scalar-valued function) into a DateTime and I keep getting the following error:
Conversion failed when converting date and/or time from character
string.
Here are the variables used throughout:
DECLARE #STARTDATETIME AS DATETIME
DECLARE #ENDDATETIME AS DATETIME
SELECT #STARTDATETIME = '8/29/2016 12:00:00'
SELECT #ENDDATETIME = '8/30/2016 12:00:00'
Column definitions:
FT_START_DATE SmallDateTime
FT_END_DATE SmallDateTime
FT_START_TIME Int
FT_END_TIME Int
The date fields do not contain timestamps. The time fields are basically 24 hour time without the colon dividers. (Example: 142350 = 14:23:50)
Here's the function that is called in my queries:
USE [PWIN171]
GO
/****** Object: UserDefinedFunction [dbo].[dbo.IPC_Convert_Time] Script Date: 9/13/2016 4:50:49 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[dbo.IPC_Convert_Time]
(
#time int
)
RETURNS time
AS
BEGIN
DECLARE #Result time
SELECT #Result = CONVERT(time
, STUFF(
STUFF(
RIGHT('000000' + CONVERT(varchar(6), #time), 6)
, 5, 0, ':')
, 3, 0, ':')
)
RETURN #Result
END
Example 1 - Fails:
This is what I'm after in general.
SELECT * FROM FT WITH (NOLOCK)
WHERE
CAST(FT_END_DATE AS DATETIME) + DBO.[dbo.IPC_Convert_Time](FT_END_TIME) BETWEEN #STARTDATETIME AND #ENDDATETIME;
Example 2 - Works:
This one runs, but it won't get records from 8/29 because the end dates will be before 12:00:00 on 8/29.
SELECT * FROM FT WITH (NOLOCK)
WHERE
FT_END_DATE BETWEEN #STARTDATETIME AND #ENDDATETIME
AND CAST(FT_END_DATE AS DATETIME) + DBO.[dbo.IPC_Convert_Time](FT_END_TIME) BETWEEN #STARTDATETIME AND #ENDDATETIME;
I suppose I could do one where I split apart my paramters and check that the end time is between the time portion of the parameters as well, but that seems to be a step in the wrong direction. The error seems to only appear when there is no other usage of FT_START_DATE or FT_END_DATE in the where clause.
The time converting function works fine in every scenario I have created. I have even tried Example 2 with parameters that would give it 100% overlap with the data covered by Example 1 in case there was bad data causing the error, but it runs fine.
I also don't know exactly where the error is occurring, because it only references the line the select statement begins on, and not the actual location in the code.
Why does it behave like this?
UPDATE:
TIMEFROMPARTS is not available because this is on SQL Server 2008
If I understand this correctly, this can be done much simpler:
Try this:
DECLARE #d DATE=GETDATE();
DECLARE #t TIME=GETDATE();
SELECT #d;
SELECT #t;
SELECT CAST(#d AS datetime)+CAST(#t AS datetime);
A pure date and a pure time can simply be added to combine them...
UPDATE Read your question again...
Try this
SELECT FT_END_DATE
,FT_END_TIME
,CAST(FT_END_DATE AS DATETIME) + DBO.[dbo.IPC_Convert_Time](FT_END_TIME) AS CombinedTime
,*
FROM FT
to see if your attempt is doing the right thing.
If yes, it might help to create a CTE and do the filter on the named column.
Sometimes the engine does not work the order you would expect this.
As CTEs are fully inlined it is quite possible, that this will not help...
SQL Server is well knwon for bringing up such errors, because a type check happens before a conversion took place...
It might be an idea to use the given SELECT with INTO #tbl to push the result set into a new table and do your logic from there...
I am running a stored procedure on SQL Server 2005 and calling it from a VB.net application.
This stored procedure was taking over 3 minutes to run and I started working on way to speed it up. Quite by accident I stumbled on a solution that reduced the run time from 3 minutes to 3 seconds (no joke, I'm dead serious).
But I don't understand why.
The only 2 parameters that I pass are a start date and an end date (used in the WHERE clause) as so:
ALTER PROCEDURE get_OrderLinessByRegion
#DateFrom DATETIME,
#DateTo DATETIME
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
blah, blah, blah
Though some testing I found that when I hard coded the dates in the stored procedure the run times were cut from 3 minutes to 3 seconds.
I ended up with this:
ALTER PROCEDURE get_OrderLinessByRegion
#DateFrom DATETIME,
#DateTo DATETIME
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #StartDate AS DATETIME
DECLARE #EndDate AS DATETIME
SET #StartDate = #DateFrom
SET #EndDate = #DateTo
blah, blah, blah
Can anyone tell me why the second version runs so much faster ?
Thanks so much !!
This sounds like a case of bad parameter sniffing. You can read this article for a detailed explanation. http://sqlinthewild.co.za/index.php/2007/11/27/parameter-sniffing/
Is it possible to execute a SQL statement that has been stored within a table as text.
I am trying to create a configuration table to drive a large number of SSRS subscriptions and don’t want to code any values directly into the report I want them all driven from a table for maintance.
E.G.
If part of one reports file name will always be the year of the previous month (2013 for example) but this needs to be generated at run time.
Can I stored this as a text field
CAST(YEAR(DATEADD(month, -1, GETDATE())) AS VARCHAR(4))
Then execute it and resolve the result into a SQL query?
If I understand your question correctly, then yes by using dynamic SQL. For example:
DECLARE #SQL NVARCHAR(4000)
DECLARE #YEAR VARCHAR(4)
SET #SQL = 'SELECT #yr = CAST(YEAR(DATEADD(month, -1, GETDATE())) AS VARCHAR(4))'
EXECUTE sp_executesql #SQL, N'#yr VARCHAR(4) OUTPUT', #yr=#YEAR OUTPUT
SELECT #YEAR
...returns 2013 into variable #YEAR.
Here I've hardcoded the query but it is a simple case to build the value of #SQL from a table's column value instead. You can then use the result from this query to build another dynamic query and so on.
Below is a subset of the above showing the SQL being taken from a table instead:
CREATE TABLE Dynamic (id INTEGER, text VARCHAR(4000) )
INSERT Dynamic values (1, 'CAST(YEAR(DATEADD(month, -1, GETDATE())) AS VARCHAR(4))')
SET #SQL = 'SELECT #yr = ' + (SELECT text FROM Dynamic WHERE id = 1)
why couldn't you?
Is it only one line of values per report?
I see 2 choices with SSRS.
1) everything in sql, you do dynamic sql.
declare #sql nvarchar(4000)
select #sql = 'select * from mytable where year = ' mavar'
from tablevalue where uniqueid = blablabla
exec sp_executesql #sql
second possibilty :
You make a first dataset in SSRS getting this value and then you evaluate the value of your condition and send it to a third dataset.
If you have multiple values, you can still imagine to get the value from a first dataset, evaluate them and send this to a subreport.
I don't know your application enought to determine the performance of this.
Until you are in SSRS, i recommand to try to find a solution in SSRS instead of Sql (but it's not a gold rule at all!!!)