Setting a variable in a SQL WHERE clause to be used in SELECT - sql

I'm using Transact-SQL with Microsoft SQL Server, and we have a query that looks like this:
SELECT Cast( Cast ( Cast(XMLBlob as XML).query(N'//continent/forest/tree/age/Text()') as nvarchar) as bigint),
AnotherField
FROM [MyDB].[dbo].[mytable]
WHERE Cast( Cast ( Cast(XMLBlob as XML).query(N'//continent/forest/tree/age/Text()') as nvarchar) as bigint)
between 10 and 100
The XML cast is an expensive operation, and since it's used in both the WHERE and SELECT, it seems like I should be able to save it away as a variable in the WHERE (which, by order of operations, is evaluated before the SELECT), and use it in the SELECT instead of having to cast again. Is this possible?

You could use an inner query where you retrieve the XML value. Then outside the inner query you both return that bigint value and filter the values you want:
SELECT innerTable.Age, innerTable.AnotherField
FROM (
SELECT Cast( Cast ( Cast(XMLBlob as
XML).query(N'//continent/forest/tree/age/Text()') as nvarchar) as bigint) AS Age,
AnotherField
FROM [MyDB].[dbo].[mytable]
) AS innerTable
WHERE innerTable.Age between 10 and 100
By the way... why do you need a bigint to store Age? If you are storing years looks like overkill, even for those trees that live thousands of years :)

Related

Select Distinct and sequence at the same time

How can I able to use Distinct on select statement along with a sequence on SQL Server
I try this sub-query but no luck I get error of
NEXT VALUE FOR function is not allowed in check constraints, default objects, computed columns, views, user-defined functions, user-defined aggregates, user-defined table types, sub-queries, common table expressions, derived tables or return statements.
Select Distinct (Select
Next Value for dbo.P_PM_TBlIF240_SEQ , 'PH70', LEFT(ToolID, LEN(ToolID) - 2) as TOOLID, UsedLife, GETDATE(), CURRENT_TIMESTAMP, 'PH70-TA'
From
Machine_ToolItem_Relationship ) from Machine_ToolItem_Relationship
Can anyone help me with this?
Solve thank for the help #Nick.McDermaid my final query looks like this.
Select
Next Value for dbo.P_PM_TBlIF240_SEQ , 'PH70', LEFT(ToolID, LEN(a.ToolID) - 2) as TOOLID, a.UsedLife, GETDATE(), CURRENT_TIMESTAMP, 'PH70-TA'
from (Select
Distinct LEFT(ToolID, LEN(ToolID) - 2) as TOOLID, UsedLife
from Machine_ToolItem_Relationship) as a

How to convert multiple varchar values into smallint

Pardon me, I was trying hard to find the answer, but most of the questions are related in the forum related to converting one value, not the whole set.
I am trying to pass the subquery values to the main query but the subquery returning varchar and the main query column is accepting smallint. I tried cast and convert but didn't help me.
select time_off_type_no
from schedtime
where activity_no in (select AT_NUMBERS from ACTIVITY where AT_ID = 105)
This query is throwing the following exception
Conversion failed when converting the varchar value '483,484,485,486,487,488,489' to data type smallint
Any advice on how to convert the values much appreciated.
Following query returning '483,484,485,486,487,488,489' and I want to convert all the values to SmallInt or int to pass it to the main query.
select AT_NUMBERS
from ACTIVITY
where AT_ID = 105
Please try nested casting like:
SELECT CAST(CAST(AT_NUMBERS AS DECIMAL) AS SMALLINT) from ACTIVITY where AT_ID=105
EDIT: Since the returned value is a comma-delimited string, I think this would help if the version of SQL Server is at least 2016
;with cte (ID) as (
Select string_split (AT_NUMBERS,',') as ID
from ACTIVITY
where AT_ID=105
)
select time_off_type_no from schedtime where activity_no in (
SELECT CAST(CAST(ID AS DECIMAL) AS SMALLINT) from cte
)
If SQL SERVER version is below 2016, we'll need to develop our own split function. You can find examples in How to split a comma-separated value to columns
Try this as an example if so, working in Sql Server 2008:
DECLARE #t TABLE
(
EmployeeID INT,
Certs VARCHAR(8000)
)
INSERT #t VALUES (1,'B.E.,MCA, MCDBA, PGDCA'), (2,'M.Com.,B.Sc.'), (3,'M.Sc.,M.Tech.')
SELECT EmployeeID,
LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) AS Certs
FROM
(
SELECT EmployeeID,CAST('<XMLRoot><RowData>' + REPLACE(Certs,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
FROM #t
)t
CROSS APPLY x.nodes('/XMLRoot/RowData')m(n)
Ref: https://blog.sqlauthority.com/2015/04/21/sql-server-split-comma-separated-list-without-using-a-function/
I think you need to split the string by comma if these (483,484,485,486,487,488,489) are individual numbers. If this is whole integer value, not even Big Int limit is like this.
See MS documentation:
https://learn.microsoft.com/en-us/sql/t-sql/data-types/int-bigint-smallint-and-tinyint-transact-sql?view=sql-server-2017
If your SQL server version is more than 2016 or more, then you can use string_split function in this way.
--Use try_cast or Try_convert to avoid any conversion error as well.
select Try_cast(value as int) Integervalue from string_split ('483,484,485,486,487,488,489',',')
Output:
Integervalue
483
484
485
486
487
488
489
--this will work if it is pure integer value, else it needs to be converted to decimal.
Please make sure to use cross apply if you are using against tables.
If it is less than 2016, you might have to build one string split function as mentioned here.
Splitting the string in sql server

Finding max value for a column containing hierarchical decimals

I have a table where the column values are like '1.2.4.5', '3.11.0.6',
'3.9.3.14','1.4.5.6.7', N/A, etc.. I want to find the max of that particular column. However when i use this query i am not getting the max value.
(SELECT max (CASE WHEN mycolumn = 'N/A'
THEN '-1000'
ELSE mycolumn
END )
FROM mytable
WHERE column like 'abc')
I am getting 3.9.3.14 as max value instead of 3.11....
Can someone help me?
Those aren't really decimals - they're strings containing multiple dots, so it's unhelpful to think of them as being "decimals".
We can accomplish your query with a bit of manipulation. There is a type build into SQL Server that more naturally represents this type of structure - hierarchyid. If we convert your values to this type then we can find the MAX fairly easily:
declare #t table (val varchar(93) not null)
insert into #t(val) values
('1.2.4.5'),
('3.11.0.6'),
('3.9.3.14'),
('1.4.5.6.7')
select MAX(CONVERT(hierarchyid,'/' + REPLACE(val,'.','/') + '/')).ToString()
from #t
Result:
/3/11/0/6/
I leave the exercise of fully converting this string representation back into the original form as an exercise for the reader. Alternatively, I'd suggest that you may want to start storing your data using this datatype anyway.
MAX() on values stored as text performs an alphabetic sort.
Use FIRST_VALUE and HIERARCHYID:
SELECT DISTINCT FIRST_VALUE(t.mycolumn) OVER(
ORDER BY CONVERT(HIERARCHYID, '/' + REPLACE(NULLIF(t.mycolumn,'N/A'), '.', '/') + '/') DESC) AS [Max]
FROM #mytable t

If I have a cast in a where clause before I check another field first will it fail?

I have a scenario where I am aggregating data between two systems. Unfortunately I am using a table adapter in Visual Studio.
Select * from prsnpsht where Cast(snp_check as bigint) > 10 and sourcereference Is Null
Union ALL
Select * from prsnpsht where sourcereference is not null
In the case above, the snp_check from the first system will be all numeric which will cast with the snp_check to bigint correctly and we know the data is from the first system because the sourcereference is null. The second system can have other characters in the snp_check field and when it tried to cast to bigint, it fails.
If I keep the structure of the query the way it is, will it attempt to cast all of the checks to big int before it analyzes the sourcereference condition, or is SQL Server smart enough to know that it should limit the data before it tries to cast the snp_check field?
I apologize in advance if this is a duplicate question, but I was unable to find it if it was answered before.
IF the SQL Server Version is 2012 or above try the following query
Select * from prsnpsht where try_convert(bigint,snp_check) > 10 and sourcereference Is Null
Union ALL
Select * from prsnpsht where sourcereference is not null
Try_Convert() returns a null value when snp_check is an invalid Bigint data
I speculate that for this query:
Select *
from prsnpsht
where Cast(snp_check as bigint) > 10 and sourcereference Is Null;
You are getting a conversion error.
In SQL Server 2012+, the solution is to use try_convert():
Select *
from prsnpsht
where try_convert(bigint, snp_check) > 10 and sourcereference Is Null;
In earlier versions, use a case:
Select *
from prsnpsht
where (case when snp_check not like '%[^0-9]%'
then convert(bigint, snp_check)
end) > 10 and
sourcereference Is Null;

Check if field is numeric, then execute comparison on only those field in one statement?

This may be simple, but I am no SQL whiz so I am getting lost. I understand that sql takes your query and executes it in a certain order, which I believe is why this query does not work:
select * from purchaseorders
where IsNumeric(purchase_order_number) = 1
and cast(purchase_order_number as int) >= 7
MOST of the purchar_order_number fields are numeric, but we introduce alphanumeric ones recently. The data I am trying to get is to see if '7' is greater than the highest numeric purchase_order_number.
The Numeric() function filters out the alphanumeric fields fine, but doing the subsequent cast comparison throws this error:
Conversion failed when converting the nvarchar value '124-4356AB' to data type int.
I am not asking what the error means, that is obvious. I am asking if there is a way to accomplish what I want in a single query, preferably in the where clause due to ORM constraints.
does this work for you?
select * from purchaseorders
where (case when IsNumeric(purchase_order_number) = 1
then cast(purchase_order_number as int)
else 0 end) >= 7
You can do a select with a subselect
select * from (
select * from purchaseorders
where IsNumeric(purchase_order_number) = 1) as correct_orders
where cast(purchase_order_number as int) >= 7
try this:
select * from purchaseorders
where try_cast(purchase_order_number as int) >= 7
have to check which column has numeric values only.
Currently, in a table every field is setted with nvarchar(max) Like tableName (field1 nvarchar(max),field2 nvarchar(max),field3 nvarchar(3)) and tableName has 25lac Rows.
But on manually Check Field2 Contain the numeric Values Only... How to Check With t-sql that in the Complete Column (Field2) has numeric Value or not/null value with Longest Length in the Column!