Filtering conditional in WHERE clause [closed] - sql-server

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have the PEN_TIPO column of a table, this column can have values 0 and 2, and in the report depending on the filter I apply the condition as follows:
declare #PEN_TIPO int = 0
(A.PEN_TIPO = #PEN_TIPO OR #PEN_TIPO = 0)
However, it will have a condition that I do not need to filter this field, ie I have to get 0 and 2 from the PEN_TIPO column.
How can I apply this filter?

It sounds like you're describing, what is commonly referred to as an optional parameter.
If the user enters a parameter value, they want to filter based on that, if not, ignore it altogether.
It would typically look something like this:
DECLARE #PEN_TIPO INT;
(A.PEN_TIPO = #PEN_TIPO OR #PEN_TIPO IS NULL)
OPTION(RECOMPILE);
Please note that I added "OPTION(RECOMPILE)" to the end of the query.
You'll want to add this to you query too, so that the optimizer can create an optimized plan based on the chosen parameter value.

Are you trying to do this ?
DECLARE #PEN_TIPO INT = NULL
SELECT *
FROM TableName
WHERE
A.PEN_TIPO = ISNULL(#PEN_TIPO, PEN_TIPO)
When #PEN_TIPO = NULL then A.PEN_TIPO = A.PEN_TIPO which will bring everything.

This is usually handled with a similar conditional where clause using NULL, but you code would if you defaulted the value to 1 or another value.
In the below proc, we default the parameter to NULL. It will remain NULL if your report / application doesn't pass in a value.
If it remains null, all rows are returned.
If a value is passed in that is 0 or 2, the filter is applied.
If a value is passed in that isn't 0 or 2, an error is raised.
Here's the proc.
create proc myProc (#PEN_TIPO int = NULL)
as
if (#PEN_TIPO IS NOT NULL) or (#PEN_TIPO NOT IN (0,2))
begin
raiserror('Invalid parameter',16,1)
end
SELECT A.*
FROM SomeTable A
WHERE (A.PEN_TIPO = #PEN_TIPO OR #PEN_TIPO IS NULL)
Aaron Bertrand has an in-depth post on these Kitchen Sink type queries.

Related

Splitting Strings then Creating Segments out of those. T-SQL [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
How do I split a csv string into this format in SQL Server?
Initial String value (A, B, C, D) into :
A-B
B-C
C-D
You can try using string_split in conjunction with lead()
select value + '-' + lead(value) over (order by value) new_value
from string_split('A,B,C,D',',')
SQL FIDDLE:
http://sqlfiddle.com/#!18/0a28f/2607
Grab a copy of NGrams8K then you could simply do this.
DECLARE #string VARCHAR(100) = 'A, B, C, D';
SELECT TheString = CONCAT(ng.Token,'-',ng.Nxt)
FROM
(
SELECT ng.Token, Nxt = LEAD(ng.Token,1) OVER (ORDER BY ng.Position)
FROM dbo.ngrams8k(#string,1) AS ng
WHERE ng.Token LIKE '%[a-z]%'
) AS ng
WHERE ng.Nxt IS NOT NULL;
Returns:
TheString
---------------------
A-B
B-C
C-D
Order is guaranteed without a sort in the execution plan.

ISNULL Not working when I am calculating the sum of two columns in the expression part of the function [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I am trying to use ISNULL (), but in the expression part of the function, instead of having a column name as the argument,I have the sum of four columns, and it should return a 0 when all of the value in the column is NULL, else the sum. for e.g., if three columns have values and corresponding value in the other column is Null, it should still return the sum of the three values. This is how I have written my query:
Select ISNULL([FY18 P1]+[FY18 P2]+[FY18 P3]+[FY18 P4],0) as [Previous YTD]
from TableA
This calculated column inside the ISNULL function is not working. Can anybody help me rewrite this expression so that it will work. What i mean when it is not working is that, it is returning a NULL when only one column is NULL but the rest of the columns have a value. Basically it should return the sum and not NULL in this case.
If any column in your concatenation IS NULL then the result will be NULL.
You need to wrap each column in IS NULL to make this column value 0 so that your addition doesn't return NULL.
SELECT ISNULL([FY18 P1],0) +ISNULL([FY18 P2],0) + ISNULL([FY18 P3],0) + ISNULL([FY18 P4],0)
This is because anything + NULL returns NULL
select 1 + 2 + 3 + NULL --returns `NULL`

What's the meaning of this simple SQL statement?

I am new to T-SQL. What is the meaning of the following statement?
BEGIN
UPDATE table_name
SET a = ISNULL(#f_flag,0)
END
Begin, End: The Begin and End is not needed. It identifies a code
block, usefull if more that one statement.
UPDATE table_name: Update the data in the table "table_name".
SET: Keyword, start the comma delimited list of column - value pairs
to update
a = : a is the column mame, to value to the right of the = is what
value will be used
ISNULL(#f_flag,0): The value to assign. In this case the IsNull checks the value of the #f_flag variable, and if it is null, then use a 0.
*Note: that there is no "WHERE" clause here, therefore, all rows in the table will be updated.

SQL Server: Computed Column Result Used In Another Computed Column

I know its not possible to have a computed column take into consideration its calculations another computed column. I found out the hard ware with the following error:
"is not allowed to be used in another computed-column definition."
So i have the following data columns, which arent neccessarily important, but just so you understand what I am doing (any other columns referenced are standard non computed columns):
HardwareAssetDepreciableValue AS CONVERT(DECIMAL(7,2),HardwareAssetPurchaseValue -
HardwareAssetSalvageValue)
HardwareAssetLifeSpan AS CONVERT(DECIMAL(6,2),DATEDIFF(day,HardwareAssetDateInstalled,
HardwareAssetEndOfLifeDate)) / 365
They are all calculated and work as expected, however what I am having issues with is a rather complicated set of calculations at best, but wondering if anyone can suggest or help with alternatives to resolving the issue of multiple computed columns.
My query is:
HardwareAssetAccumulatedDepreciationValue AS CASE WHEN HardwareAssetDepreciationMethodID
= '1' THEN CONVERT(DECIMAL(7,2),((HardwareAssetDepreciableValue / HardwareAssetLifeSpan)
/ 365)) WHEN HardwareAssetDepreciationMethodID = '2' THEN CONVERT(DECIMAL(7,2),
HardwareAssetAccumulatedDepreciationValue + ((1.5 *(1/HardwareAssetLifeSpan))*
HardwareAssetBookValue)/365) ELSE CONVERT(DECIMAL(7,2),
HardwareAssetAccumulatedDepreciationValue + ((2 *(1/HardwareAssetLifeSpan))
*HardwareAssetBookValue)/365) END
Any help or advice is appreciated!
This error is not allowed to be used in another computed-column definition. occurs when you have used computed column to calculate another column value...
it seems you have below computed column
HardwareAssetDepreciableValue
And then you ,use the same to calculate below computed column
THEN CONVERT(DECIMAL(7,2),((HardwareAssetDepreciableValue / HardwareAssetLifeSpan)
/ 365))
you should not do like that..instead ,you should use base calculation
but wondering if anyone can suggest or help with alternatives to resolving the issue of multiple computed columns.
at present,there are no better alternatives ,one solution i could think of is a view to query the base table and use already existing computed values
A computed column is good for a "one off" IMHO.
For something a tad bit complex, I like to create a scalar user defined function, and wrap the "mini logic" in it.
Here is a simple Northwind example. It doesn't make alot of pratical sense, but demonstrates.
Now, I don't like the below udfExampleUdfTwoDoubleUdfOne idea. But it could work for you.
Its an idea for the arsenal of tools. Which is because you asked for alternate ideas.
Use Northwind
GO
create function dbo.udfExampleUdfOne(#OrderID as int, #ProductID int, #UnitPrice money )
returns int
as
begin
declare #returnValue int = 0
select #returnValue = ISNULL(#OrderID,0) + ISNULL(#ProductID,0) + ISNULL(#UnitPrice,0)
return #returnValue;
end;
GO
create function dbo.udfExampleUdfTwoDoubleUdfOne(#udfOneResult int)
returns int
as
begin
declare #returnValue int = 0
select #returnValue = ISNULL(#udfOneResult,0) * 2
return #returnValue;
end;
GO
SELECT TOP 1000 [OrderID]
,[ProductID]
,[UnitPrice]
,[Quantity]
,[Discount]
, MyValueOne = dbo.udfExampleUdfOne(OrderID , ProductID , UnitPrice)
, MyValueTwoWhichIsActuallyDoubleValueOne = dbo.udfExampleUdfTwoDoubleUdfOne(dbo.udfExampleUdfOne(OrderID , ProductID , UnitPrice))
FROM [Northwind].[dbo].[Order Details]
APPEND
So trying to mimic your example
create function dbo.udfComputeHardwareAssetDepreciableValue(#HardwareAssetPurchaseValue int, #HardwareAssetSalvageValue int )
returns int
as
begin
declare #returnValue int = 0
select #returnValue = ISNULL(#HardwareAssetPurchaseValue,0) - ISNULL(#HardwareAssetSalvageValue,0)
return #returnValue;
end;
create function dbo.udfComputeHardwareAssetLifeSpan(#HardwareAssetDateInstalled int, #HardwareAssetEndOfLifeDate int )
returns int
as
begin
declare #returnValue int = 0
select #returnValue = CONVERT(DECIMAL(6,2),DATEDIFF(day,#HardwareAssetDateInstalled,
#HardwareAssetEndOfLifeDate)) / 365
return #returnValue;
end;
Then write a third UDF that encapsulates your HardwareAssetAccumulatedDepreciationValue IF/THEN/CASE logic.
You ~could~ pass in the computed columns into the new udfComputeHardwareAssetAccumulatedDepreciationValue function as well.
Even if you are new , you should spend a little time struggling with this concept as its a tool in the best to avoid RBAR/CURSORS.
You can get the Northwind db from here:
https://technet.microsoft.com/en-us/library/ms143221(v=sql.105).aspx
Yes, its very old, but simple demos can be created from it.
you can make both of the columns user defined Function , i was looking for it but finally got , the function can access all the columns computed ND NON Computed...
thank you

Querying all records are true in sql-server - is casting expensive performance wise

I have a table with a column of bit values. I want to write a function that returns true if all records of an associated item are true.
One way I found of doing it is:
Select #Ret = CAST(MIN(CAST(IsCapped as tinyInt)) As Bit)
from ContractCover cc
Inner join ContractRiskVersion crv on cc.ContractRiskId = crv.ContractRiskId
WHERE crv.ContractVersionId = #ContractVersionId
AND cc.IsActive = 1
return #ret
But is the casting to int to get the minimum expensive? Should I instead just be querying based on say:
(count(Id) where IsCapped = 0 > 0) returning false rather than doing the multiple casts?
In the execution plan it doesn't seem like calling this function is heavy in the execution (but I'm not too familiar with analysing query plans - it just seems to have the same % cost as another section of the stored proc of like 2%).
Edit - when I execute the stored proc which calls the function and look at the execution plan - the part where it calls the function has a query cost (relative to the batch) : 1% which is comparable to other sections of the stored proc. Unless I'm looking at the wrong thing :)
Thanks!!
I would do this with an exists statement as it will jump out of the query from the moment it finds 1 record where IsCapped = 0 where as your query will always read all data.
CREATE FUNCTION dbo.fn_are_contracts_capped(#ContractVersionId int)
RETURNS bit
WITH SCHEMABINDING
AS
BEGIN
DECLARE #return_value bit
IF EXISTS(
SELECT 1
FROM dbo.ContractCover cc
JOIN dbo.ContractRiskVersion crv
ON cc.ContractRiskId = crv.ContractRiskId
WHERE crv.ContractVersionId = #ContractVersionId
AND cc.IsActive = 1
AND IsCapped = 0)
BEGIN
SET #return_value = 0
END
ELSE
BEGIN
SET #return_value = 1
END
RETURN #return_value
END
Compared to the IO required to read the data, the cast will not add a lot of overhead.
Edit: wrapped code in a scalar function.
Casting in the SELECT would be CPU and memory bound. Not sure how much in this case--under normal circumstances we usually try to optimize for IO first, and then worry about CPU and memory second. So I don't have a definite answer for you there.
That said, the problem with this particular solution to your problem is that it won't short-circuit. SQL Server will read out all rows where ContractVersionId = #ContractVersionId and IsActive = 1, convert IsCapped to an INT, and take the min, where really, you can quit as soon as you find a single row where IsCapped = 0. It won't matter much if ContactVersionId is highly selective, and only returns a very small fraction of the table, or if most rows are capped. But if ContactVersionId is not highly selective, or if a high percentage of the rows are uncapped, then you are asking SQL Server to do too much work.
Second consideration is that scalar-valued functions are a notorious performance drag in SQL Server. It is better to create as an in-line table function if possible, eg:
create function AreAllCapped(#ContractVersionId int)
returns table as return (
select
ContractVersionId = #ContractVersionId
, AreAllCapped = case when exists (
select *
from ContractCover cc
join ContractRiskVersion crv on cc.ContractRiskId = crv.ContractRiskId
where crv.ContractVersionId = #ContractVersionId
and cc.IsActive = 1
and IsCapped = 0
)
then 0 else 1 end
)
Which you then can call using CROSS APPLY in the FROM clause (assuming SQL 2005 or later).
Final note: taking the count where IsCapped = 0 has similar problems. It's like the difference between Any() and Count() in LINQ, if you are familiar. Any() will short-circuit, Count() has to actually count all the elements. SELECT COUNT(*) ... WHERE IsCapped = 0 still has to count all the rows, even though a single row is all you need to move on.
Of course, it is a known fact that a bit column can't be passed as an argument to an aggregate function (and thus, if it needs to be passed, you have to cast it as an integer first), but bit columns can be sorted by. Your query, therefore, could be rewritten like this:
SELECT TOP 1 #Ret = IsCapped
FROM ContractCover cc
INNER JOIN ContractRiskVersion crv on cc.ContractRiskId = crv.ContractRiskId
WHERE crv.ContractVersionId = #ContractVersionId
AND cc.IsActive = 1
ORDER BY IsCapped;
Note that in this particular query it is assumed that IsCapped can't be NULL. If it can, you'll need to add an additional filter to the WHERE clause:
AND IsCapped IS NOT NULL
Unless, of course, you would actually prefer to return NULL instead of 0, if any.
As for the cost of casting, I don't really have anything to add to what has already been said by Filip and Peter. I do find it a nuisance that bit data require casting before aggregating, but that's never something of a primary concern.

Resources