ISNULL - ON clause - sql

I'm trying to use the ISNULL, COALESCE or CASE on this ON clause but it gives me an error.
'Incorrect syntax near the keyword 'between'.
I need to check one date from one table between two dates from other one but if the date doesn't exist on the second table then use the previous date.
talbe1 t1 JOIN table2 t2
ON t1.code = t2.code
AND ISNULL(cast(dateadd(d,-1,t1.UtcFinishTime) as date) BETWEEN t2.TransactionFirstDate and t2.TransactionLastDate,cast(dateadd(d,-2,t1.UtcFinishTime) as date) BETWEEN t2.TransactionFirstDate and t2.TransactionLastDate)
Many thanks.

Your syntax is incorrect because ISNULL needs to be part of the statement as it returns the value; and not the entire statement, so you're likely after something like:
AND ISNULL(
cast(dateadd(d,-1,t1.UtcFinishTime) as date),
cast(dateadd(d,-2,t1.UtcFinishTime) as date)
)
BETWEEN t2.TransactionFirstDate and t2.TransactionLastDate
Or using a CASE functionality.
But I'd advice you for performance sake to make a check before hand and then have a specific query for either situation.

Could not check it but off the top of my head, below query may help-
SELECT *
from table1 t1 JOIN table2 t2
ON t1.code = t2.code AND
CASE
WHEN dateadd(day,-1,t1.UtcFinishTime) is null
THEN cast(dateadd(day,-2,t1.UtcFinishTime) as date)
END
BETWEEN t2.TransactionFirstDate and t2.TransactionLastDate

Related

tsql - extract only a portion of a dynamic string

I have a table with a column that holds a string such as:
xx-xx-xxx-84
xx-25-xxx-xx
xx-xx-123-xx
I want to go ahead and query out the numbers only, but as you can see, the numbers are placed at different places in the string every time. Is there away to query for only the numbers in the string?
Thank you,
I appreciate your time!
This requires repeated application of string functions. One method that helps with all the nesting is using OUTER APPLY. Something like this:
select t3.col
from t outer apply
(select t.*, patindex(t.col, '[0-9]') - 1 as numpos) t1 outer apply
(select t1.*, substring(t1.col, t1.numpos, len(t1.col)) as col2) t2 outer apply
(select t2.*,
(case when col2 like '%-%'
then substring(t2.col, charindex('-', t2.col))
else t2.col
end) as col3
) t3
The easy way (sure if only 'x' and '-' are in strings):
SELECT REPLACE(REPLACE(s,'x',''),'-','') FROM T
Or if X can be any non digital character then using PATINDEX() function:
SELECT S, SUBSTRING(S,
PATINDEX('%[0-9]%',s),
PATINDEX('%[0-9][^0-9]%',s)
+PATINDEX('%[0-9]',s)
+1
-PATINDEX('%[0-9]%',s)) as digit
FROM T

Select the last non-NULL value when current row is NULL

I know that there are a lot of solutions for this but unfortunately I cannot use partition or keyword TOP. Nothing I tried on earlier posts works.
My table looks like this:
The result I want is when any completion percentage is NULL it should get the value from last non-value completion percentage, like this:
I tried this query but nothing works. Can you tell me where I am going wrong?
SELECT sequence,project_for_lookup,
CASE WHEN completion_percentage IS NOT NULL THEN completion_percentage
ELSE
(SELECT max(completion_percentage) FROM [project_completion_percentage] AS t2
WHERE t1.project_for_lookup=t2.project_for_lookup and
t1.sequence<t2.sequence and
t2.completion_percentage IS NOT null
END
FROM [project_completion_percentage] AS t1
SQL Server 2008 doesn't support cumulative window functions. So, I would suggest outer apply:
select cp.projectname, cp.sequence,
coalesce(cp.completion_percentage, cp2.completion_percentage) as completion_percentage
from completion_percentage cp outer apply
(select top 1 cp2.*
from completion_percentage cp2
where cp2.projectname = cp.projectname and
cp2.sequence < cp.sequence and
cp2.completion_percentage is not null
order by cp2.sequence desc
) cp2;
Does this work? It seems to for me. You were missing a parenthesis and had the sequence backwards.
http://sqlfiddle.com/#!3/465f2/4
SELECT sequence,project_for_lookup,
CASE WHEN completion_percentage IS NOT NULL THEN completion_percentage
ELSE
(
SELECT max(completion_percentage)
FROM [project_completion_percentage] AS t2
WHERE t1.project_for_lookup=t2.project_for_lookup
-- sequence was reversed. You're on the row t1, and want t2 that is from a prior sequence.
and t2.sequence<t1.sequence
and t2.completion_percentage IS NOT null
--missing a closing paren
)
END
FROM [project_completion_percentage] AS t1

Main T-SQL WHERE function seems to be wrongly applied to a subquery

This query returns a set of dates from tblValue whose FieldValue is type nvarchar(4000)
SELECT t1.FieldValue FROM (SELECT FieldValue
FROM tblValue
WHERE FieldID = 4) t1
WHERE DateAdd(day, -90, t1.FieldValue) <= GETDATE()
This works, but instead of hard-coding the FieldID of 4, I'd like to get all FieldValues for those which have the type "Expiration".
This query returns 4.
SELECT FieldID FROM tblField WHERE FieldType = 'Expiration'
So, I expect this query's innermost subquery to return 4, and then to have the DateAdd applied only to those Expiration values which are yielded from t1 in the outermost subquery, which is what happens in the working first example.
SELECT t1.FieldValue FROM (SELECT FieldValue
FROM tblValue
WHERE FieldID = (SELECT FieldID FROM tblField WHERE FieldType = 'Expiration')) t1
WHERE DateAdd(day, -90, t1.FieldValue) <= GETDATE()
But I get the error
"Conversion failed when converting date and/or time from character string."
which to me suggests that the DateAdd is being applied to all values of tblValue, not only to those which are yielded by the subquery which returns t1. There is probably a technical reason for it, but it doesn't seem right to me. For some reason
WHERE FieldID = 4) t1
is not equivalent to
WHERE FieldID = (SELECT FieldID FROM tblField WHERE FieldType = 'Expiration')) t1
It just so happens that if I leave off the final WHERE clause of the erroring query I get the same set of dates as in the working query. So t1 should not be presenting any values which the DateAdd should have a problem with. But there it is. I'm puzzled as to why.
This happens because of the particular execution plan that the optimizer produces. Depending on how it chooses to combine the comparison and filtering operations of the various clauses, it can do either one or the other first.
In this case, it's trying to perform the date conversion and comparison before applying the FieldType filter.
It's a well-known issue but inherent to the behavior of the SQL optimizer -- this is a similar issue with a different datatype: https://connect.microsoft.com/SQLServer/feedback/details/333312/error-8114-converting-data-type-varchar-to-numeric
There are ways around this, but they are not always straightforward and usually require you to force specific order of execution.
The below works for me, although I understand that the CASE technique is not always 100% effective. From this fiddle:
SELECT t1.FieldValue FROM (SELECT FieldValue
FROM tblValue
WHERE FieldID = (SELECT FieldID FROM tblField WHERE FieldType = 'Expiration')) t1
WHERE CASE WHEN ISDATE(t1.FieldValue) = 1 THEN DateAdd(day, -90, t1.FieldValue) ELSE '1/1/2900' END <= GETDATE()
I guess you want this?
SELECT * FROM tblValue v
JOIN tblField f ON v.FieldID = f.FieldID
WHERE f.FieldType = 'Expiration' AND DateAdd(day, -90, v.FieldValue) <= GETDATE()
To categorize this as wrongly applied is not fair
You don't get to control which rows TSQL will evaluate
With a hard 4 the optimizer did that first
Without a hard 4 the query optimizer had to be ready for anything and moved it to later
The query optimizer even considers a derived table fair game to optimize
If you just look at the query plan you can see the order
Try
SELECT *
FROM tblValue v
JOIN tblField f
ON v.FieldID = f.FieldID
AND f.FieldType = 'Expiration'
AND DateAdd(day, -90, v.FieldValue) <= GETDATE()

SQL query taking too long - help for better performance

I am running a stored procedure in which i have the following query
SELECT TOP 1 #TopValue = t2.myDecimal
from table1 t1, table2 t2
where t1.ID = t2.table1ID
and CONVERT( VARCHART(8), t1.Created, 112 ) = #stringYYYYMMDD
and t1.Term = #Label"
TopRate is Decimal(8,6)
stringYYYYMMDD is a string representing a date in the format YYYYMMDD
Label is a simple varchar(8)
This query is called for every row of my data set, that can be from 10 to 5000. If I comment this query, the procedure execution time is under 2 seconds. With the query included, it just never ends.
I am using Microsoft SQL Server management studio 2008 R2
Thank you for your help
First, you should use explicit join syntax. Second, it is suspicious whenever you have a top without an order by. So, your query as I see it is:
select TOP 1 #TopValue = t2.myDecimal
from table1 t1 join
table2 t2
on t1.ID = t2.table1ID
where CONVERT( VARCHART(8), t1.Created, 112 ) = #stringYYYYMMDD and t1.Term = #Label"
You can speed this up with some indexes. But, before doing that, you want to change the date comparison:
where t1.Created >= convert(datetime, #stringYYYYMMDD, 112) and
t1.Created < convert(datetime, #stringYYYYMMDD, 112) + 1 and
t1.Term = #Label
Moving the function from the column to the constant makes the comparison "sargable", meaning that indexes can be used for it.
Next, create the indexes table1(Term, Created, Id) and table2(table1Id). These indexes should boost performance.

Select Rows Where A Column Contains Any Result From A SubQuery

If have a table that contains a column of concatenated data using a delimiter i.e. 11111_22222_33333 (I know this is bad practice, but that's the data I have to work with)
I need to write a query that returns all rows that contain specific values of 22222 where the specific values are the result of a sub query.
So, what I am doing is follows...
SELECT * FROM myTable WHERE myColumn IN (SELECT [Name] FROM subTable)
This runs but doesnt return any results as it's specifically matching 1111_2222_3333 to 2222. So what I need is a way of using a LIKE or something similar
SELECT * FROM myTable WHERE myColumn LIKE (SELECT [NAME] FROM subTable)
gives the error
Msg 512, Level 16, State 1, Line 1
Subquery returned more than 1 value. This is not permitted when the subquery follows
=, !=, <, <= , >, >= or when the subquery is used as an expression.
How would this be accomplished please? I am using Sql Server 2008 R2 to develop, but the solution needs to also be compatible with Server 2005
Your subquery is returning more than one value and LIKE will not work with subquery, what you need to use is EXISTS here try this
SELECT * FROM myTable a
WHERE EXISTS (SELECT 1 FROM subTable b
WHERE a.myColumn LIKE '%' + b.[NAME] + '%')
SELECT
t1.*
FROM myTable t1
join (
SELECT distinct [Name] FROM subTable
) x
on t1.myColumn like '%' + x.[name] + '%'
You can use a JOIN with the LIKE clause to get the result:
select *
from mytable t
inner join subtable s
on t.mycolumn like '%'+s.name+'%'
See SQL Fiddle with Demo